Multithreading Geschwindigkeit erhöhen



  • Hallo,
    mir ist mein Berechnungsprogramm etwas zu langsam. Wo liegen den die "Zeitfresser" in meinem Programm und wie kann ich diese optimieren. Die Berechnung wird in 4 Threads ausgelagert (4 Kerne durch i5-3570K).

    Wäre es sinnvoller *LUT13 für jeden Thread einzeln zu erstellen. Weil jetzt greifen alle 4 Threads auf das gleiche Array zu, kommt es dabei evtl. zu Verzögerungen? Genauso mit den var1,var2,var3... die ja mehrfach in den Threads verwendet werden?

    global:
    unsigned int *LUT13 = (unsigned int*)malloc(sizeof(unsigned int)*200*200*200*13);
    double var1, var2, var3,...;
    long double lvar1, lvar2, lvar3....;
    int Auswertung[200];

    Jetzt werden im "mainthread" 4 Threads aufgerufen und gewartet bis diese fertig sind.

    Die 4 Threads durchlaufen jeweils 50*200*200 Schritte:
    for(int A=0; A<50; A++) { //Die anderen dann von 50-100, 100-150, 150-200
    for(int B=0; B<200; B++) {
    for(int C=0; C<200; C++) {
    //Hier steht jeweils die "gleiche" Berechnung
    }
    }
    //Hier steht der Vergleich
    }

    Berechnung:
    Bei der Berechnung stehen ca 40x solche Zeilen. Es wird also sehr oft auf die gleichen globalen Variablen in allen 4 Threads zugegriffen.

    z.b:
    lvar1= lvar1 + LUT13[A*200*200*13+B*200*13+C*13+0] * var1 * var2;

    Vergleich:
    Anschließend werden die lvar1 aufsummiert und per if/else mit einem >= verglichen. D.h. nur ein if/else pro A. Je nach Fall wird 1 oder 0 in eine weitere gloable Variable Auswertung[A] gespeichert.



  • MarkusH. schrieb:

    Hallo,
    mir ist mein Berechnungsprogramm etwas zu langsam.

    Was heißt das? Wie ist das Verhältnis zwischen Single- und Multithreaded?

    Ansonsten sind die Informationen recht dürftig für Fernwartung.



  • Danke für deine Antwort.

    4Threads 70 Sekunden
    1Thread 19 Sekunden

    Da lässt sich wohl gar nicht mehr viel optimieren, ist ja fast 4x schneller.
    Dann muss ich wohl den Singlethread schneller bekommen.

    Am if/else Vergleich kann ich nichts ändern, dieser ist notwenig.

    Die 40 Zeilen Rechnerei ist ja dann die einzige Option etwas zu optimieren.

    lvar1= lvar1 + LUT13[A*200*200*13+B*200*13+C*13+0] * var1 * var2;

    Die lvar1 sind halt von Typ long double, da LUT13[] aus Werten besteht, die fast den kompletten unsigned int Bereich ausfüllen und ich diese ja 50*200*200 aufaddiere werden, so entstehen sehr große Zahlen.

    Ist die Rechnerei mit long double merklich langsamer als z.b. mit int? Wenn ja kann ich evtl. die Datenstruktur umstellen?
    Kostet ein Mix von int, double... in einer Gleichung ebenfalls merklich Zeit?



  • Poste mal den Code (Codetags nicht vergessen). So kann Dir hier keiner richtig helfen.



  • - du solltest soweit es möglich ist keine globalen variablen nutzen!
    - zum optimieren kannst du vielleicht rechnungen zusammen ziehen etc...
    - evt. ist auch eine überlegung wert ob wirklich 4 threads sein müssen, manchmal ist es auch effektiver mit 1 oder 2 wenigern...
    ( damit meine ich z.B.:
    1.thread arbeitet - 10 sek
    2.thread arbeitet - 20 sek
    3.thread arbeitet - 30 sek
    4.thread arbeitet - 40 sek --> d.h thread 1 wartet 30 sek nichts tuend... nun könntest du die aufgabe von thread 4 soweit die rechnungen und der code dies zulassen vielleicht in den thread 1 und 2 "aufteilen" so das die "gesamtwarte zeit" geringer wird...)

    - ansonsten überleg dir wo kann es zum "flaschenhals" kommen und wie kannst du das umgehen?

    hoffe ist wenigstens ein ansatz der dir hilft 😉
    lg



  • __Gast schrieb:

    - zum optimieren kannst du vielleicht rechnungen zusammen ziehen etc...

    sry hab eben gesehen ist etwas undeutlich...
    damit meine ich wenn du z.b. in einer schleife

    for(i=0;i<ix;i++)
    {
      x=3+1+1; 
      x= x+30; 
    }
    

    kannst du auch

    for(i=0;i<ix;i++)
    {
      x=((3+1+1)+30);  
    }
    

    ob das dann aber wirklich schneller ist kommt auf den speziellen fall an...
    muss evt. gemessen werden... dies ist von rechnung zu rechnung unterschiedlich...
    ohne deine rechenoperationen zu sehen ist dies schwierig einzuschätzen... 😉



  • __Gast schrieb:

    sry hab eben gesehen ist etwas undeutlich...
    damit meine ich wenn du z.b. in einer schleife [...]

    Solche Mini-Optimierungen sind schon lange nicht mehr noetig. Man sollte so schreiben, dass der Code ordentlich wird.

    __Gast schrieb:

    nun könntest du die aufgabe von thread 4 soweit die rechnungen und der code dies zulassen vielleicht in den thread 1 und 2 "aufteilen" so das die "gesamtwarte zeit" geringer wird...)

    Das sollte verhaeltnismaessig wenig ausmachen. Der Scheduler kann hunderte oder tausende von Threads problemlos handhaben. Die paar Millisekunden Erzeugungsaufwand sollten hier nicht viel ausmachen.



  • Am Array wird das eher nicht liegen, dafür liegen die Zugriffe räumlich zu weit auseinander. Meine Vermutung ist, dass das Problem hiermit zusammenhängt:

    double var1, var2, var3,...;
    long double lvar1, lvar2, lvar3....;
    

    lvar1, lvar2 etc. liegen auf diese Weise im Speicher direkt nebeneinander, d. h. mit einiger Wahrscheinlichkeit in der selben cache line. Da die Variablen von jedem Thread in jedem Schleifendurchlauf angefasst werden, stellt jeder Thread (bzw. jeder CPU-Kern) bei jedem Durchlauf fest, dass sein Cache nicht mehr aktuell ist und muss sich mit den anderen synchronisieren (was dauert). Das Problem wird häufig "Cache Ping Pong" genannt; befrag mit dem Begriff die Suchmaschine deines Vertrauens, wenn du mehr Details willst.

    Wenn meine wilde Vermutung richtig ist, wird sich das Problem dadurch lösen lassen, dass du in jedem Thread statt in lvar1... in einer lokalen Variable hochzählst und erst am Ende einmal zuweist.


Anmelden zum Antworten