Performance



  • slapy schrieb:

    das dauert bei 1MB größe ca. 30 Sekunden, wenn ich aber dabei eine Variable zählen lasse und diese ausgeben lasse, verfünfacht sich die Zeit bis die Datei fertig ausgelesen wurde, also ca. 150 Sekunden. -> ist das normal???

    ja, das liegt wohl daran das die festplatte blockorientiert ist. d.h. auch wenn du nur ein zeichen anforderst liesst sie einen ganzen block - und das dauert. also kann man gleich einen block in den ram laden und von dort aus weiter verarbeiten da man dann keine wartezeiten mehr hat(bezueglich der festplatte)



  • slapy schrieb:

    wenn ich aber dabei eine Variable zählen lasse und diese ausgeben lasse, verfünfacht sich die Zeit bis die Datei fertig ausgelesen wurde, also ca. 150 Sekunden. -> ist das normal???

    ja, das ist völlig normal. die ausgabe auf den bildschirm ist etwas enorm langsames.
    mab behebt es am einfachsten, indem man statt

    cout<<i;
    

    lieber

    if(i%1024==0)cout<<i;
    

    schreibt.

    außerdem will man meistens statt

    if(i%1024==0)cout<<i<<'\n';
    

    lieber

    if(i%1024==0)cout<<i<<'\r';
    

    haben.

    wenn möglich lass auch seekg weg.

    und wenn dann noch was geholt werden soll, lies immer blöcke zu 1024 bytes ein statt einzelne bytes und verarbeite die blöcke dann selber.

    also erstmal

    if(in){
       do{
         int const BUFSIZE=1024;
         char buf[SIZE];
         int size=in.read(buf,BUFSIZE);
         for(int j=0;j<size;++j)
            tuwas(buf[j]);
         cout<<i<<'\r';
       }while(in);
    }
    

    oder so.
    damit haste schonmal echt gute performance.

    Desweiteren würde ich gerne wissen, ob es noch einen schnelleren Weg gibt einzelne Chars aus einer Datei auszulesen, bzw. diese auch zu schreiben?

    zum lesen ist memory mapping (siehe CreateFileMapping() oder mmap()) normalerweise noch schneller und auch sehr einfach zu verwenden. zum schreiben, wenn die datei auch wachsen soll, lassen wir es am besten erstmal bei ofstream. man bekommt es zwar schneller, aber das ist bereits sehr mühsam.



  • der block(eigentlich sogar die nächsten paar blöcke) bleibt aber im cache der festplatte,womit die nächsten aufrufe automatisch schneller sind, weil keine lese aktion durchgeführt werden muss. inweiweit das aber noch zutrifft nachdem seek aufgerufen wurde, weis ich nicht.



  • hm, ok, aber klärt das auch die Frage warum das "cout<<.." die Zeit vervielfacht?

    int ch; // int nicht char!
    while((ch=in.get()) != EOF)
    {
    
    }
    

    - darf das wirklich funktionieren, in der Referenz steht nicht, dass .get() den Dateizeiger eins weitersetzt, also dachte ich dass ich mit seekg immernoch den Dateizeiger weitersetzen muss?!

    Nochmal zu den Blockweise-Aufbau: Wie groß ist ein Block? ein Zeichen ist doch schon 1 Byte lang. mit welcher funktion wäre es sonst ratsam einen größeren Block auszulesen?
    Vielen Dank soweit.
    slapy



  • oh da hat während ich geschrieben habe, volkard schon die meisten meiner Fragen beantwortet, vielen Dank !!!



  • volkard schrieb:

    if(in){
       do{
         int const BUFSIZE=1024;
         char buf[SIZE];
         int size=in.read(buf,BUFSIZE);
         for(int j=0;j<size;++j)
            tuwas(buf[j]);
         cout<<i<<'\r';
       }while(in);
    }
    

    oder so.
    damit haste schonmal echt gute performance.

    wenn man's noch schneller haben will sollte man noch die sich in der schleife befindenen variablen nach aussen verlegen bzw. weg lassen(size)



  • oder man entledigt sich dieser sorgen und verlässt sich voll und ganz auf den compiler der das eh rausoptimiert 😉



  • Cpt.Tanga schrieb:

    wenn man's noch schneller haben will sollte man noch die sich in der schleife befindenen variablen nach aussen verlegen bzw. weg lassen(size)

    nach außen legen kann der compiler generell aleine, wenns PODs sind. nach innen legen ist aber meist nicht möglich, weil man den wert des letzen schleifendurchlaufs haben muss.
    also macht der mensch nach möglichkeit alles so lokal wie möglich und nach aussen legen darf der compiler, wie er lust hat.

    schauen wir genauer:

    if(in){
       do{
         int const BUFSIZE=1024;//kostenlos, da inline-ersetzung wie makro
         char buf[SIZE];//sollte kostenlos sein, da nach außen gelagert. 
            //schlimmstenfalls ADD SP,1024, also einen takt und am blockende noch einen
         int size=in.read(buf,BUFSIZE);//size landet ex in AX. behalten ist kostenlos.
         for(int j=0;j<size;++j)//j natürlich auch in ein register stecken und davon ausgehen, daß tuwas inline ist
            tuwas(buf[j]);
         cout<<i<<'\r';
       }while(in);
    }
    


  • Cpt.Tanga schrieb:

    volkard schrieb:

    if(in){
       do{
         int const BUFSIZE=1024;
         char buf[SIZE];
         int size=in.read(buf,BUFSIZE);
         for(int j=0;j<size;++j)
            tuwas(buf[j]);
         cout<<i<<'\r';
       }while(in);
    }
    

    oder so.
    damit haste schonmal echt gute performance.

    wenn man's noch schneller haben will sollte man noch die sich in der schleife befindenen variablen nach aussen verlegen bzw. weg lassen(size)

    Wenns richtig schnell sein soll läßt man das cout weg und benutzt was eigenes, das bestenfalls putchar aufruft


  • Mod

    edit: müll



  • hab die datei(release) mal im debugger betrachtet-musste sie allerdings noch ein wenig umschreiben da sie sonst nicht lauffaehig gewesen weare:

    if(in)
    	{
    	do {
    		int const BUFSIZE=1024;
    		char buf[BUFSIZE]={0};
    		in.read(buf,BUFSIZE);
    		for(int j=0;buf[j];++j)
    			tuwas(buf[j]);
    		cout<<buf<<'\r';
    		} while (in);
    	endl(cout);
    	};
    

    nun gut allerdings hat dieser code auch nicht mehr so viel mit volkards gemein aber was solls :P.
    heraus kam dass die variablen nicht nach aussen verlegt worden. wobei BUFSIZE durch eine konstante(0x400) ersetzt wurde(also keine eigene speicherzelle in anspruch nahm, und buf jedes mal neu belegt wurde(was allerdings auch an ...={0}; liegen koennte).



  • compiler? optimierungslevel?



  • normalerweise haben streams einen eingebauten puffer von 4kb oder so. seek löscht jedoch den puffer und deshalb bringt die pufferung in deinem programm nichts. da die lesefunktionen aber sowieso den fileseekpointer um die gelesene zahl an bytes weiterschieben, kannst du seek auch weglassen. dann sollte es recht flott gehen.

    allerdings haben dateioperationen von haus aus einen ziemlichen overhead. deshalb ist es immer deutlich schneller, ein paar kb auf einmal zu schreiben/lesen als jedes byte einzeln.



  • vc 6.0 einfache release optimiert auf geschwindigkeit.



  • Also danke für die ganzen Optimierungstipps, mit in.read geht das wirklich extrem viel schneller.
    Ich habe aber noch ein Problem was die Blöcke angeht:
    Ich will einfach mal mit diesem code eine Datei kopieren, das funktioniert ziemlich schnell aber eben nicht ganz. Ich habe eine 1,11KB große datei file1.dat und die kopierte Datei file2.dat ist aber leider nur 1KB groß. Warum?

    ifstream in("file1.dat",ios::binary);
            ofstream out("file2.dat",ofstream::binary);
    
            in.seekg(0, ios::end);
            unsigned long file_size = in.tellg();
            in.seekg(0, ios::beg);                         
    
            char *buffer;
            buffer = new char [file_size];
            in.read(buffer,file_size);
            out.write(buffer,file_size);
    

    Bin für jeden Hinweis bezüglich des Problems oder auch verbesserungswürdiger Performance dankbar!
    slapy



  • kann eigentlich nicht passieren-der code sieht ok aus. -musst mal nachsehen was denn in der kopierten datei anders ist als in der original. zur not kannst du ja auch copy mal aus <algorithm> verwenden.


Anmelden zum Antworten