Sha1 Hash von Datei erstellen zu langsam

Alles rund um die Programmierung mit Qt
Antworten
KillSwitch
Beiträge: 4
Registriert: 15. September 2009 16:46

Sha1 Hash von Datei erstellen zu langsam

Beitrag von KillSwitch »

Hallo,

ich habe derzeit ein sehr seltsames Problem für das ich keine Erklärung habe:
Ich erstelle einen Thread der mir rekursiv ein Verzeichnis durchläuft und erstellt für jede Datei ein QRunnable das von QThreadPool abgearbeitet wird. In diesen QRunnable's wird ein SHA1 Hash von der Datei berechnet.
Das Problem ist, dass ich lange nicht die maximale Leistung eines Rechners damit Auslasten kann. Auf einem alten AMD XP 3000 single Core kriege ich gerade mal ~65% CPU Auslastung hin bei ca. 40MB/s (meine Platte schafft 65MB/s und andere Hash-Tools nutzen dies auch aus)
Warum fährt hier Qt mit angezogener Handbremse?

Hier der Code aus dem QRunnable:

Code: Alles auswählen

void ShareHasherPrivate::run()
{
    QFile file(m_filePath);
    if(!file.open(QIODevice::ReadOnly)) return;

    QCryptographicHash hash(QCryptographicHash::Sha1);

    static char buffer[SHA1_BUFFER_SIZE];
    qint64 result = 0;

    while(!file.atEnd())
    {
        result = file.read(buffer, SHA1_BUFFER_SIZE);
        hash.addData(buffer, result);
    }
    file.close();

}
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag von pfid »

Nur so als grundlegende Frage (hilft deinem Problem vermutlich nicht), aber wieso machst du nicht sowas wie:

Code: Alles auswählen


   QFile file;
   ...               // open etc

   QByteArray unhashed = file.readAll();
   QByteArray hashed = QCryptographicHash::hash(QCryptographicHash::Sha1);

   ...              // close etc

[edit] Alle deine Objekte der Klasse ShareHasherPrivate teilen sich den statischen Buffer (so wie ichs verstanden hab sind das deine Threads). Es ist daher ungünstig, alle Threads auf dem selben Buffer arbeiten zu lassen ;)
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

@pfid: Das ist eine denkbar schlechte Idee da Du nicht weißt wie groß die Datei ist. Allerdings hast Du recht - der Puffer sollte nicht zu klein sein. Ich benutze für sowas immer zwischen 1 und 10MB.

Das mit dem statischen Array ist natürlich falsch und kann nicht gehen.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Deine anderen Programme machen dies auch in verschiedenen Threads und somit gleichzeitig von verschiedenen Positionen der Platte?
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag von pfid »

Christian81 hat geschrieben:@pfid: Das ist eine denkbar schlechte Idee da Du nicht weißt wie groß die Datei ist.
Kommt auf die Dateien an. Sind selbige so groß, dass ich mit meiner Aktion das System ausbremse, geb ich dir recht. Ansonsten sehe ich da nur einen kleinen Geschwindigkeitsvorteil.

Aber genaue Angaben wurden ja nicht gemacht =)
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Wenn ich so ein Tool schreiben würde sollte auch eine 1GB-Datei gehasht werden können... :)
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
KillSwitch
Beiträge: 4
Registriert: 15. September 2009 16:46

Beitrag von KillSwitch »

Danke für die vielen Antworten und sorry für meine späte Antwort... mein Modem ging am Tag meines Postings noch in Rauch auf!!!

Der static buffer ist natürlich ein grober Fehler von mir, ist schon lange gefixt ;-) trotzdem thx.

Gehasht werden sollen Dateien mit beliebiger Größe. Daher ist ein readAll nicht zu verwenden.
Das Problem ist nun, wenn ich den Buffer zu klein mache, schrumpft die CPU Auslastung und somit die Geschwindigkeit enorm (~40%). Lasse ich mehrere Threads mit einer kleinen BufferSize parallel laufen, so gehen zwei Threads noch mit ca ~60%. Bei 3 Threads wird so viel auf der Platte hin und her gesprungen, dass ich den sha1 Hash auch auf Papier rechnen könnte :-D
Bei einer Großen Buffersize habe ich enorme Sprünge in der CPU Auslastung. Aber selbst wenn ich hier zwei Threads laufen lassen (sozusagen, einer rechnet während der andere liest) bekomme ich keine Vollauslastung des Systems zustande.

Mir scheint, das die "angezogene Handbremse" hier das lesen der Daten von Platte ist.
Daher nun folgende Idee: (ich frag erstmal ob das Sinn macht, bevor ich mir die Mühe mache das zu implementieren)
Würde ein Thread, der für das sequenzielle Lesen von Platte Sinn machen? Dieser Thread würde von den anderen Threads anfragen bekommen, diese sequenziell abarbeiten und die gelesenen Daten zurück geben. Davon erhoffe ich mir weniger "Sprünge" auf der Platte, und man könnte mit den WorkerThreads besser skalieren. Würde so was Sinn machen?
Antworten