Beschleunegt C / C ++ Datei I / O ouni Schweess ze briechen

Beschleunegt C / C ++ Datei I / O ouni Schweess ze briechen

Viruerteel

Et gĂ«tt sou en einfachen a ganz nĂ«tzlechen Utility op der Welt - Bdelta, an et ass geschitt, datt et scho ganz laang an eisem Produktiounsprozess agebonne war (obwuel et net mĂ©iglech war seng Versioun z'installĂ©ieren, awer et war definitiv net dĂ©i lescht verfĂŒgbar). Mir benotzen et fir seng virgesinn Zweck - binĂ€re Patches bauen. Wann Dir kuckt wat am Repository ass, gĂ«tt et e bĂ«ssen traureg: TatsĂ€chlech war et viru laanger ZĂ€it verlooss a vill dovun ass ganz veroudert (meng frĂ©iere Kolleg huet eng KĂ©ier e puer Ännerungen do gemaach, awer dat war viru laanger ZĂ€it) . Am Allgemengen hunn ech dĂ©cidĂ©iert dĂ«s MatiĂšre z'erliewen: Ech hunn forkĂ©iert, erausgehĂ€it wat ech net geplangt hunn ze benotzen, de Projet geplĂ«nnert cm maachen, inlined "waarm" Mikrofunktiounen, hu grouss Arrays aus dem Stack gelĂ€scht (an Arrays vu variabelen LĂ€ngt, dĂ©i mech Ă©ierlech gesot "Bomb") hunn de Profiler nach eng KĂ©ier gelaf - a fonnt datt ongefĂ©ier 40% vun der ZĂ€it op schreiwen...

Also wat ass mat fwrite?

An dësem Code gëtt fwrite (a mengem spezifesche Testfall: e Patch tëscht no 300 MB Dateien bauen, d'Inputdaten sinn ganz an der Erënnerung) Millioune Mol mat enger klenger Puffergréisst genannt. SelbstverstÀndlech wÀert dës Saach méi lues sinn, an dofir wéilt ech dës Schimmt iergendwéi beaflossen. Et gëtt nach kee Wonsch verschidden Aarte vun Datequellen ëmzesetzen, asynchron I/O, ech wollt eng méi einfach Léisung fannen. Déi éischt Saach, déi am Kapp komm ass, war d'Puffergréisst ze erhéijen

setvbuf(file, nullptr, _IOFBF, 64* 1024)

awer ech hunn keng bedeitend Verbesserung am Resultat kritt (elo huet fwrite ongeféier 37% vun der ZÀit ausgemaach) - dat heescht datt et nach ëmmer net eng Saach ass fir dacks Daten op Disk ze schreiwen. Wann Dir "ënnert der Hood" vu fwrite kuckt, kënnt Dir gesinn datt eng SpÀr / SpÀr FILE Struktur an esou eppes geschitt (Pseudo-Code, all Analyse gouf ënner Visual Studio 2017 duerchgefouert):


size_t fwrite (const void *buffer, size_t size, size_t count, FILE *stream)
{
   size_t retval = 0;
   _lock_str(stream);   /* lock stream */
   __try
   {
      retval = _fwrite_nolock(buffer, size, count, stream);
   }
   __finally 
   {
       _unlock_str(stream);   /* unlock stream */
   }
   return retval;
}

Laut dem Profiler stellt _fwrite_nolock nëmmen 6% vun der ZÀit aus, de Rescht ass iwwerhead. A mengem besonnesche Fall ass d'Fuedemsécherheet kloer iwwerkill, also wÀert ech et opferen andeems ech de fwrite Uruff ersetzen mat _fwrite_nolock - Dir musst net emol clever mat Argumenter sinn. Total: dës einfach Manipulatioun reduzéiert d'KÀschte fir d'Resultat opzehuelen, wat an der Originalversioun bal d'Halschent vun der ZÀit ausgaang ass. Iwwregens, an der POSIX Welt gëtt et eng Àhnlech Funktioun - fwrite_opgespaart. Allgemeng gëllt datselwecht fir Fread. Also, andeems Dir e Paar #defines benotzt, kënnt Dir eng komplett Cross-Plattform Léisung ouni onnéideg SpÀr kréien, wann se net néideg sinn (an dat geschitt zimlech dacks).

fwrite, _fwrite_nolock, setvbuf

Loosst eis vum urspréngleche Projet ewechkommen a eis op d'Tester vun engem spezifesche Fall konzentréieren: eng grouss Datei (512 MB) a ganz klenge Stécker schreiwen - all Stéck ee Byte. Testsystem: AMD Ryzen 7 1700, 16 GB RAM, 7200 rpm Festplack, 64 MB Cache. Windows 10 1809, d'BinÀrdatei gouf als 32-Bit gebaut, Optimiséierunge sinn aktivéiert, d'Bibliothéik ass statesch verlinkt.

Probe fir den Experiment:


#include <chrono>
#include <cstdio>
#include <inttypes.h>
#include <memory>

#ifdef _MSC_VER
#define fwrite_unlocked _fwrite_nolock
#endif

using namespace std::chrono;

int main()
{
    std::unique_ptr<FILE, int(*)(FILE*)> file(fopen("test.bin", "wb"), fclose);
    if (!file)
        return 1;

    constexpr size_t TEST_BUFFER_SIZE = 256 * 1024;
    if (setvbuf(file.get(), nullptr, _IOFBF, TEST_BUFFER_SIZE) != 0)
        return 2;

    auto start = steady_clock::now();
    const uint8_t b = 77;
    constexpr size_t TEST_FILE_SIZE = 512 * 1024 * 1024;
    for (size_t i = 0; i < TEST_FILE_SIZE; ++i)
        fwrite_unlocked(&b, 1, sizeof(b), file.get());

    auto end = steady_clock::now();
    auto interval = duration_cast<microseconds>(end - start);
    printf("Time: %lldn", interval.count());

    return 0;
}

D'Variabelen wĂ€erten TEST_BUFFER_SIZE sinn, a fir e puer FĂ€ll ersetzen mir fwrite_unlocked mat fwrite. Loosst eis mam fwrite Fall ufĂ€nken ouni explizit d'PuffergrĂ©isst ze setzen (kommentĂ©ieren setvbuf an den assoziĂ©ierten Code): ZĂ€it 27048906 ”s, Schreifgeschwindegkeet - 18.93 MB / s. Loosst eis elo d'PuffergrĂ©isst op 64 KB setzen: ZĂ€it - 25037111 ÎŒs, Geschwindegkeet - 20.44 Mb/s. Loosst eis elo d'Operatioun vum _fwrite_nolock testen ouni setvbuf ze ruffen: 7262221 ”s, Geschwindegkeet - 70.5 Mb/s!

Als nÀchst experimentéiere mer mat der Puffergréisst (setvbuf):

Beschleunegt C / C ++ Datei I / O ouni Schweess ze briechen

D'Donnéeën goufen duerch Moyenne 5 Experimenter kritt; Ech war ze faul fir d'Feeler ze berechnen. Wat mech ugeet, 93 MB / s wann Dir 1 Byte op eng normal HDD schreift ass e ganz gutt Resultat, Dir musst just déi optimal Puffergréisst auswielen (a mengem Fall ass 256 KB just richteg) an ersetzen fwrite mat _fwrite_nolock/fwrite_unlocked ( am Fall wann thread Sécherheet net néideg ass, natierlech).
Och mat fread an Àhnleche Konditiounen. Well ech keng Hardware-Maschinn mat Linux bei der Hand hunn (Singleboard-Computeren zielen net), hunn ech beschloss e limitéierten Experiment op enger virtueller Maschinn ze maachen (Hyper-V, OpenSUSE 15, GCC 8.3.1) - den Muster ass am Prinzip d'selwecht: "plakeg" fwrite 20 Mb/s, fwrite + 256 KB Puffer produzéiert 23 Mb/s, fwrite_unlocked mam selwechte Puffer - 35 Mb/s (64-Bit binÀr, versammelt g++ -o2 - s -static-libgcc -static-libstdc++ fwrite_test. cpp -o fwrite_test).

Afterword

Den Zweck vun dësem Artikel ze schreiwen war eng einfach an efficace Technik a ville FÀll ze beschreiwen (Ech sinn nach ni op d'_fwrite_nolock/fwrite_unlocked Funktiounen begéint, si sinn net ganz populÀr - awer ëmsoss). Ech maachen net wéi wann d'Material nei ass, awer ech hoffen datt den Artikel fir d'Gemeinschaft nëtzlech ass.

Source: will.com

Kaaft zouverlĂ€sseg Hosting fir Site mat DDoS Schutz, VPS VDS Server đŸ”„ Kaaft zouverlĂ©issegt WebsĂ€ithosting mat DDoS-Schutz, VPS VDS Server | ProHoster