HDD-Benchmark liesst zu schnell ein



  • Hi,

    ich möchte grade einen kleinen HDD-Benchmark schreiben.
    Die Schreib-Ergebnisse sind ganz in Ordnung und realistisch, wie ich finde (meine Seagate ~21 MB/s und die WD ~38 MB/s);

    Nur bei dem Lesetest habe ich unrealistische Geschwindigkeiten von 250 - 300 MB/s.
    Ich nehme stark an, dass er die geschriebene Datei noch im RAM hat und auch aus diesem statt von der Festplatte liesst.
    (Übrigens: Wenn ich die Testdateigrösse auf 500 MB stelle, bekomme ich plötzlich realistische Ergebnisse; ich habe 512 MB RAM)

    Meine Frage ist nun: Wie kann ich dies umgehen? Soll ich etwa irgendwie den RAM löschen oder geht es einfacher?

    Hier der Quellcode (nicht sehr lang):

    //#include "stdafx.h"
    #include <windows.h>
    #include <iostream.h>
    #include <fstream.h>
    #include <string.h>
    #include <conio.h>
    
    int main(void)
    {
    	char drive[] = "c";
    	char file[] = ":\\temp_bench.tmp";
    	char dir[256];
    
    	const int SIZE_TO_WRITE = 100*1024; //Groesse der Testdatei in KB angeben
    	const int ONE_KB = 1024;
    	char *oneKB = new char[ONE_KB]; // ein Kilobyte
    	for(int j=0; j<ONE_KB; ++j)
    		oneKB[j] = '0';
    
    	cout << "Dies ist ein simpler Festplatten-Geschwindigkeitstest." << endl;
    	cout << "Sie sollten mindestens " << SIZE_TO_WRITE/1024 << " MB auf dem entspr. Laufwerk frei haben." << endl;
    	cout << "Welches Laufwerk wollen Sie testen? (nur den Laufwerksbuchstaben eingeben)" <<endl  << endl;
    	cout << "Laufwerk: ";
    	cin >> drive;
    	if(drive[1] != '\0'){
    		cout << "Ungueltiges Laufwerk." << endl;
    		getch();
    		return 0;
    	}
    
    	strcpy(dir, drive);
    	strcat(dir, file);
    
    	fstream out(dir, ios::out | ios::binary);
    	if(!out){
    		cout << "Fehler beim erzeugen der Datei "<< dir << endl;
    		getch();
    		return 0;
    	}
    
    	cout << "Test wird gestartet:" << endl;
    
    	//cout <<"Schreibe Datei: " << dir <<" ..." <<endl;
    	cout << "Schreibtest..." << endl;
    	int w_startTime = GetTickCount();
    	for(int i=0;i<SIZE_TO_WRITE;++i){
    		out.write(oneKB, ONE_KB);
    	}
    	out.close();
    	int w_usedTime = (GetTickCount() - w_startTime);
    
    	cout << "Lesetest..." <<endl;
    	fstream in(dir, ios::in | ios::binary);
    	if(!in){
    		cout << "Fehler beim oeffnen der Datei "<< dir << endl;
    		getch();
    		return 0;
    	}
    
    	char *readData = new char[SIZE_TO_WRITE*1024];
    	int r_startTime = GetTickCount();
    	in.read(readData, SIZE_TO_WRITE*1024); //liefert unrealistisches Ergebnis
    	in.close();
    	int r_usedTime = (GetTickCount() - r_startTime);
    
    	float w_transferrate = (SIZE_TO_WRITE/1024.0f)/(w_usedTime/1000.0f);
    	float r_transferrate = (SIZE_TO_WRITE/1024.0f)/(r_usedTime/1000.0f);
    	cout << "----------------------------------------------------------" << endl;
    	cout << "Ende des Tests: " << endl << endl;
    	cout << w_usedTime << " ms wurden benoetigt, um " << SIZE_TO_WRITE/1024 << " MB zu schreiben." <<endl;
    	cout << r_usedTime << " ms wurden benoetigt, um " << SIZE_TO_WRITE/1024 << " MB zu lesen." <<endl;
    	cout << "Tranferrate - schreiben: " << w_transferrate << " MB/s" << endl;
    	cout << "Tranferrate - lesen    : " << r_transferrate << " MB/s" << endl;
    
    	remove(dir);
    	delete[] readData;
    	delete[] oneKB;
    	getch();
    	return 0;
    }
    


  • Hallo,

    du schreibst in einer Schleife Blöcke von 1024 Bytes aber liest alles auf einmal "100 MB" ein. Da solltest du auch in einer Schleife von 1024 ( oder besser eine variable Puffergröße zum Lesen und Schreiben von 1 - 64 KB ?!) lesen.



  • WoWe schrieb:

    Hallo,

    du schreibst in einer Schleife Blöcke von 1024 Bytes aber liest alles auf einmal "100 MB" ein. Da solltest du auch in einer Schleife von 1024 ( oder besser eine variable Puffergröße zum Lesen und Schreiben von 1 - 64 KB ?!) lesen.

    Genau das habe ich auch schon gemacht (in 1 KB-Blöcken lesen).
    Das Problem blieb trotzdem genau das gleiche. Das macht also keinen Unterschied. Wirklich.

    Edit:
    Aber rein von der Vereinheitlichung her hast Du nat. recht. Da brauche ich keine 100 MB auf dem Heap zu reservieren.
    Beim Schreibtest habe ich es deswegen in 1 KB-Blöcke aufgeteilt, weil da - im Gegensatz zum lesen - die Performance besser ist, wie an einem Stück.
    Sonst hätte ich da wahrscheinlich auch am Stück geschrieben. 🙂



  • Hallo fit,

    ich habe dein Beispiel mal ausprobiert und komme da auch auf extrem hohe Werte. Ich denke das liegt am Cache.
    Mit fstream hab ich noch nicht viel gemacht. Hab das Beispiel mal etwas verändert:

    //---------------------------------------------------------------------------
    #include <windows.h>
    #include <conio.h>
    #include <iostream>
    #pragma hdrstop
    
    #pragma argsused
    
    using namespace std;
    
    typedef unsigned long ulong;
    
    int main(int argc, char* argv[])
    {
        HANDLE hFile;
        char drive[] = "c";
        char file[] = ":\\temp_bench.tmp";
        char dir[256];
    
        ulong bytesRead = 0, bytesWritten = 0;
        const int SIZE_TO_WRITE = 100*1024*1024;
        //const int BUF_SIZE = 1024;
        const int BUF_SIZE = 8 * 1024;
        BYTE *writeData = new BYTE[BUF_SIZE+1];
        for(int j=0; j<BUF_SIZE; ++j)
            writeData[j] = random(255);
    
        cout << "Dies ist ein simpler Festplatten-Geschwindigkeitstest." << endl;
        cout << "Sie sollten mindestens " << SIZE_TO_WRITE/1024/1024 << " MB auf dem entspr. Laufwerk frei haben." << endl;
        cout << "Welches Laufwerk wollen Sie testen? (nur den Laufwerksbuchstaben eingeben)" <<endl  << endl;
        cout << "Laufwerk: ";
        cin >> drive;
        if(drive[1] != '\0'){
            cout << "Ungueltiges Laufwerk." << endl;
            getch();
            return 0;
        }
    
        strcpy(dir, drive);
        strcat(dir, file);
    
        hFile = CreateFile(dir,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,NULL);
        if ( hFile == INVALID_HANDLE_VALUE ) return 0;
    
        cout << "Test wird gestartet:" << endl;
    
        cout << "Schreibe Datei: " << dir <<" ..." <<endl;
        cout << "Schreibtest..." << endl;
        int w_startTime = GetTickCount();
        for( ulong i=0; i < SIZE_TO_WRITE; i += bytesWritten ){
            WriteFile( hFile, writeData, BUF_SIZE, &bytesWritten, NULL );
        }
        CloseHandle( hFile );
        int w_usedTime = (GetTickCount() - w_startTime);
    
        cout << "Lesetest..." <<endl;
        hFile = CreateFile(dir,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,NULL);
        if ( hFile == INVALID_HANDLE_VALUE ) return 0;
    
        BYTE *readData = new BYTE[BUF_SIZE+1];
        //char *readData = new char[SIZE_TO_WRITE*1024];
        int r_startTime = GetTickCount();
        for( ulong k=0; k < SIZE_TO_WRITE; k += bytesRead ){
            ReadFile( hFile, readData, BUF_SIZE, &bytesRead, NULL );
        }
        CloseHandle( hFile );
        int r_usedTime = (GetTickCount() - r_startTime);
    
        float w_transferrate = (SIZE_TO_WRITE/1024.0f/1024.0f)/(w_usedTime/1000.0f);
        float r_transferrate = (SIZE_TO_WRITE/1024.0f/1024.0f)/(r_usedTime/1000.0f);
        cout << "----------------------------------------------------------" << endl;
        cout << "Ende des Tests: " << endl << endl;
        cout << w_usedTime << " ms wurden benoetigt, um " << SIZE_TO_WRITE/1024/1024 << " MB zu schreiben." <<endl;
        cout << r_usedTime << " ms wurden benoetigt, um " << SIZE_TO_WRITE/1024/1024 << " MB zu lesen." <<endl;
        cout << "Tranferrate - schreiben: " << w_transferrate << " MB/s" << endl;
        cout << "Tranferrate - lesen    : " << r_transferrate << " MB/s" << endl;
    
        remove(dir);
        delete[] readData;
        delete[] writeData;
        getch();
        return 0;
    }
    //---------------------------------------------------------------------------
    

    Damit komme ich auf "normale" Werte beim Lesen.
    Bei 8 MB BUF_SIZE komme ich auf meinem Notebook auf (W/R) 12/13 MB/s und auf meiner WS auf 28/29 MB/s.



  • @WoWe: Vielen Dank erstmal für Deine Hilfe.
    Ich wollt es halt erstmal irgendwie mit fstream hinbekommen, weil ich mich mit WINAPI nicht so gut auskenne.
    Wenn es nicht richtig geht werde ich auf Deine Lösung zurückgreifen.

    Ich habe es jetzt mit folg. Zeilen zw. der Schreib- und Leseop. probiert:

    cout << "Loesche Cache..." << flush;
    char *memClearer = new char[RAMSizeToDel]; //Groesse lasse ich vom Benutzer eingeben und dann multiplizieren mit (0,8..0,9)
    delete[] memClearer;
    cout << "fertig." << endl;
    

    Die Lösung liefert dann zwar realistische Ergebnisse, aber das "löschen" dauert sehr lange und macht das System lahm. Und wenn ich weniger lösche (z.B. Faktor 0,5) sind irgendwie immer noch verwertbare Reste im RAM.

    Hat vielleicht noch jmd. eine Idee?
    Vielleicht gibts ja irgendwelche Compiler-Optionen die weiterhelfen???



  • CreateFile aus der WinAPI kennt das Flag FILE_FLAG_NO_BUFFERING. Das könnte helfen. 🙂



  • Ja, aber ich wollte es ja möglichst mit fstream machen...



  • Warum?

    Mit Standard C++ ist es nicht möglich, das Caching abzuschalten. Das geht nur über betriebssystemspezifische Funktionen.

    Oder machst du wirklich lieber sowas:

    char* Huge = new char[ReallyHugeInt];
    delete[] Huge;
    

    ? 😉



  • btw:
    fstreams sind von vornherein gepuffert.



  • Ok, dann muss ich mich wohl geschlagen geben und WINAPI lernen. 😉
    So langsam glaube ich, dass es garkeinen Sinn mehr macht, zu versuchen, so viel wie möglich Standard-C++ zu proggen.



  • @WoWe:

    const int BUF_SIZE = 8 * 1024; 
        BYTE *writeData = new BYTE[BUF_SIZE+1]; 
        for(int j=0; j<BUF_SIZE; ++j) 
            writeData[j] = random(255);
    

    Ehmm...für mich sieht es aber eher so aus, als ob Du 8 KB anstatt 8 MB gepuffert hast.
    Die "+1" in "new BYTE[BUF_SIZE+1]; " kannst Du, soweit ich das sehe weglassen,
    da Du ja in der Schleife nur bis zum (BUF_SIZE-1)ten Element gehst.



  • Jo, sorry. Da war ich in meinem Text um eine 1000er Potenz zu hoch. Mit KB hab ich irgendwie ein Problem :D, ich denk immer mit MB fängt alles an 😃

    Die "+1" hab ich nur drin, weil es ab und zu mal mit der Adressierung ein Problem gibt (zählt's von 0 oder von 1). Ein Byte mehr oder weniger, wen juckts, aber ich bekomm auf jeden Fall keinen bösen Programmabsturz wenn ich mal Programmteile von X nach Y verwende.



  • OK, wenn mans so sieht ... 😉

    Ich habe den Code grade mal getestet mit etwa 128 KB Cache liefert er bei mir ganz gute Ergebnisse: Segate - 32/32 WD: 42/43

    Ich werde den Bechmark dann wohl auf dieser Basis weiter ausbauen.
    Vielen Dank noch mal.



  • 42/43 MB/s ???

    Was hast du für einen Controller/CPU und wie schnell ist deine Platte (5400/7200/10000) ?

    Sind ja irgendwie Traumwerte ?!



  • Kleine Frage am Rande:
    Warum nimmst du nicht ein kostenloses ausgereiftes Tool zum HD-Benchmark und vergleichst die Werte mit denen deines Programms? 🙂



  • Naja, Eigenheim ist immer besser wie Miete !!!



  • cd9000 schrieb:

    Warum nimmst du nicht ein kostenloses ausgereiftes Tool zum HD-Benchmark und vergleichst die Werte mit denen deines Programms? 🙂



  • Was ist denn ausgereift ? Was ist denn wenn beim BS Wechsel von X nach Y kein Update des ausgereiften Tools vorhanden ist ?

    Also wenn es irgendwie möglich ist, verlasse/vergleiche ich die Situationen mit meinen eigenen Tools.

    Ich möchte auch nur mit meinen eigenen Programmen die relativen Unterschiede zwischen System 1 und System 2 feststellen. Dann hab ich das in eigener Hand wenn z.B. die Hardware geändert wird.



  • Du scheinst nicht ganz zu verstehen, was ich meine.

    Ich meine, woher willst du wissen, dass dein Programm richtige Werte liefert? Wenn du doch die richtigen richtigen Werte deiner Platte gar nicht kennst? Das Programm liefert vielleicht immer 10MB/s mehr als richtig ist. Ohne einen Vergleich merkst du das nie.

    Also hol dir am besten irgendein Tool, mess die Geschwindigkeit deiner Platte damit und versuch herauszufinden, warum dein Tool andere Werte liefert (falls es andere liefert).



  • Doch, ich weiß was du meinst. Aber mir reicht der Vergleich von "meinem" Progamm auf unterschiedlichen Systemen. Ich muss nicht wissen ob das jetzt 10 MB/s sind oder 20 MB/s, sondern das mit dem gleichen Programm auf unterschiedlichen Systemen unterschiedliche Werte gemessen werden. Ich vergleiche da Prozentual.


Anmelden zum Antworten