Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von corpsman »

Hallo Zusammen,

Ich habe ein Programm geschrieben in dem ich "Arbeiten" auf Threads aufteile, die Threads synchronisieren hier und da via Critical Sections.
Um die CPU optimal aus zu lasten erzeuge ich Pro Kern einen Thread.
Unter Linux scalliert dies auch recht Brauchbar: Bei der Verdoppelung der Threads von 2 auf 4 verringert sich die Rechenzeit von 7s auf 3s. Auf meinem Privaten Windows Rechner ebenfalls. (Beide CPU's haben 4-Cores)
Starte ich das selbe Programm nun aber auf der Arbeit dann benötigt die Berechnung egal wie viele Threads > 1 immer 9s (im Single Tread Mode 3-4s), hier habe ich einen Intel I7 mit 8 Kernen. Habe auch schon versucht sämmtliche Wartebereiche der Critical Sections zu deaktivieren, bringt alles nichts, sobald ich die mehreren Threads aktiviere bricht die Performance immer auf 9s ein (selbst wenn ich andere Aufgaben wähle die im Single Thread mode andere Zeiten haben). Die Berechneten Ergebnisse sind immer korrekt.

Ich weis das ist recht nah an Glaskugel lesen, aber habt ihr ne idee woran das liegen kann ?

Allgemein an Windows kann es nicht liegen, auf dem Privaten Rechner funktioniert es ja. Ich Tippe darauf dass mein Arbeits PC irgend ein Tool / Gruppenrichtlinie hat, bei der dieser Effekt eintritt. So ist z.B. Bereits bekannt, dass der "TOpenDialog" bei mir auf Arbeit teilweise bis zu 30s beim öffnen Braucht, weil der Virenscanner da wohl immer erst alle möglichen Anfragen beim Anzeigen der Netzlaufwerke prüft ...

Komischerweise funktioniert mein Race Condition Beispiel ( https://corpsman.de/index.php?doc=beisp ... _condition ) auch auf der Arbeit wie erwartet. Daher habe ich Aktuell noch die Hoffnung, dass es evtl. doch an meiner Implementierung liegt, aber auch hier dann die Frage warum geht es bei 2 von 3 Rechnern und beim 3. nicht :?:
--
Just try it

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6208
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von af0815 »

Schon mal probiert die Executionzeit des jeweiligen Thread zu messen. Damit klar wird, ist es innerhalb des Threads oder ausserhalb.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

schoschy
Beiträge: 24
Registriert: Di 18. Okt 2022, 15:46

Re: Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von schoschy »

Moin,

wenn es ein Intel der aktuellen Generation ist, könnte es an der Nutzung von Performance- bzw. Effizienz-Cores liegen.
Bei ST Anwendungen wird gerne mal der Performance-Core angesteuert.
Wenn dann noch AV dazwischen geht und auf einem "kleinen" Kern landet, eventuell weil nur 2 Performance-Cores vorhanden sind, könnte das der Grund sein.
Ist aber auch nur aus meiner Glaskugel :lol:

Grüße

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von Socke »

schoschy hat geschrieben:
Fr 18. Nov 2022, 07:44
wenn es ein Intel der aktuellen Generation ist, könnte es an der Nutzung von Performance- bzw. Effizienz-Cores liegen.
Bei ST Anwendungen wird gerne mal der Performance-Core angesteuert.
Wenn dann noch AV dazwischen geht und auf einem "kleinen" Kern landet, eventuell weil nur 2 Performance-Cores vorhanden sind, könnte das der Grund sein.
Das könnte man doch lösen, indem die Threads oder der ganze Prozess auf die Performance-Cores gepinnt werden?
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von corpsman »

ok das mit den Performance Cores habe ich jetzt nicht direkt verstanden, aber das Zeitmessen da hätte ich echt auch drauf kommen können :roll: . Das baue ich übers we mal ein, testen werde ich es erst am Mo auf arbeit können ...
--
Just try it

PascalDragon
Beiträge: 829
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von PascalDragon »

corpsman hat geschrieben:
Fr 18. Nov 2022, 17:15
ok das mit den Performance Cores habe ich jetzt nicht direkt verstanden, aber das Zeitmessen da hätte ich echt auch drauf kommen können :roll: . Das baue ich übers we mal ein, testen werde ich es erst am Mo auf arbeit können ...
Wie ist die volle Bezeichnung deines Prozessors?

Mit Performance Cores ist gemeint, dass es relativ aktuelle Intel Prozessoren gibt, bei denen nicht alle Cores gleichwertig sind, sondern in sogenannte Performance und Efficency Cores unterteilt sind. Letztere sind dabei etwas behaglicher als die ersteren, damit mehr Energie gespart werden kann. Wenn du nun blind so viele Threads wie Cores erzeugst, kann es sein, dass die Threads, die auf den Efficency Cores laufen, den Rest dann ausbremsen. Um zu entscheiden, ob das überhaupt zutreffen kann, ist es jedoch wichtig deinen genauen Prozessor zu wissen.
FPC Compiler Entwickler

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von corpsman »

Also ich hab nu das ganze mal auf meinem ArbeitsPC laufen lassen:
Gen 5, 1315 survivors = 44%, genetic diversity = 40, time to calculate = 9s(1s 1s 1s 1s)
Interessant ist der Hintere Teil: 9s(1s 1s 1s 1s)
Das Bedeutet, dass die einzelnen Threads alle jeweils 1s gebraucht haben (also wohl doch alles gut ist) und dann weitere 8s im Haupthread verplempert wurden um deren Ergebnisse zusammen zu führen -> ich also an der Falschen Stelle gesucht habe...
Lasse ich den exakt selben Code im Single Thread laufen
Gen 4, 1168 survivors = 39%, genetic diversity = 40, time to calculate = 2s(2s)
Sieht man, dass das Zusammenführen der Thread Ergebnisse in unter 1s gemacht wird (hier sogar "0s")

Zur Frage nach meiner CPU sagt mir windows folgendes:
Caption DeviceID MaxClockSpeed Name NumberOfCores Status
Intel64 Family 6 Model 140 Stepping 1 CPU0 2995 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz 4 OK
Möge die Suche beginnen und danke für den Denkanstoß
--
Just try it

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von corpsman »

So meine Zeitmessungen zeigen Ergebnisse und nun kann ich euch auch endlich mal ein bischen Code Zeigen:
Gen 3, 1167 survivors = 39%, genetic diversity = 40, time to calculate = 9s(1s 1s 2s 1s[W=7s])
=> der Task der lang dauert sind in dem Fall die 7s = Waittime

Mein Code sieht im Prinzip so aus:

Code: Alles auswählen

      // multithreaded loop: index 0 is reserved, start at 1
      // 1. die ganzen Threads mit den "Teilaufgaben" starten
      i := IndivCalcDelta + 1;
      For indivIndex := 0 To high(fIndivThreads) Do Begin
        assert(fIndivThreads[indivIndex].IsStateIdle());
        fIndivThreads[indivIndex].StartWork(i, min(i + IndivCalcDelta, p.population), SimStep);
        i := i + IndivCalcDelta + 1;
      End;
      // 2. Der Main Thread übernimmt natürlich auch einen Teil der muss ja eh warten auf die anderen Threads
      Start := GetTickCount64;
      For indivIndex := 1 To IndivCalcDelta Do Begin // Das Element 0 wird ignoriert !
        If (peeps[indivIndex]^.alive) Then Begin
          simStepOneIndiv(peeps[indivIndex], simStep);
        End;
      End;
      delta := delta + (GetTickCount64 - Start);

      // Warten darauf, dass alle threads "fertig" sind ---------------- Hier gehen die 7s kaputt
      Start := GetTickCount64();
      b1 := true;
      While b1 Do Begin
        b1 := false;
        For i := 0 To high(fIndivThreads) Do Begin
          If Not fIndivThreads[i].IsStateIdle() Then Begin
            CheckSynchronize(1);
            b1 := true;
          End;
        End;
      End;
      waittime := waittime + (GetTickCount64 - start);     // ---------- Ende hier gehen die 7s Kaputt
      //..
      //Ausgabe Waittime als W= und 
Der Code meiner Threads ist dabei recht simpel:

Code: Alles auswählen

Procedure TThreadIndivs.Execute;
Var
  indivIndex: Integer;
Begin
  While Not Terminated Do Begin
    Case fState Of
      isIdle: Begin
          sleep(1);
        End;
      isRunning: Begin
          fWorkingStartTime := GetTickCount64;
          // Mache die Arbeit
          For indivIndex := FFirstindex To FLastIndex Do Begin
            If (peeps[indivIndex]^.alive) Then Begin
              simStepOneIndiv(peeps[indivIndex], fsimStep);
            End;
          End;
          fWorkingDelta := fWorkingDelta + (GetTickCount64() - fWorkingStartTime);
          fState := isIdle; // Arbeit getan, dann wieder zurück in Idle
        End;
    End;
  End;
End; 

Function TThreadIndivs.IsStateIdle: Boolean;
Begin
  result := fState = IsIdle;
End;  

Function TThreadIndivs.StartWork(FirstIndex, LastIndex, simStep: integer
  ): Boolean;
Begin
  result := IsStateIdle();
  If Not Result Then exit;
  FFirstindex := FirstIndex;
  FLastIndex := LastIndex;
  fsimStep := simStep;
  fState := isRunning;
End; 
=> Anscheinend ist es wohl so, dass mein "warten" auf alle Threads nicht ideal ist, bzw auf meinem Arbeits PC katastrophal, auf Linux und meinem Privaten Windows Rechner ja wohl kein Thema..
Hat einer nen Vorschlag wie man das "richtig" besser macht ?
--
Just try it

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von corpsman »

Also ich hab die WarteRoutine noch mal genauer vermessen.

Code: Alles auswählen

 b1 := true;
      While b1 Do Begin
        b1 := false;
        For i := 0 To high(fIndivThreads) Do Begin
          If Not fIndivThreads[i].IsStateIdle() Then Begin
            CheckSynchronize(0); // -- 1 -> 0
            b1 := true;
          End;
        End;
      End;    
So ist es schon mal deutlich schneller Anstatt 9s nur noch 5s, da der Single Thread aber dennoch nur 3s Braucht, bin ich im MultiThread immer noch 2s Langsamer als wie wenn ich es Single Threaded rechnen lasse :roll:

Dieses Warten an der Stelle dauert Minimal 0ms, maxilam 15 ms, da es aber Pro Durchlauf 300mal gemacht werden muss ergibt sich 4,5s = (300*0.015s) Warten...

[Edit]
Hier mal geschaut wie häufig welches warten vorkommt:
Gen 5, 1285 survivors = 43%, genetic diversity = 40, time to calculate = 4s(1s 1s 2s 1s[W=3s 0 16])
0: 84, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 81, 16: 135
84 Mal ohne Warten
81 Mal 15ms
135 Mal 16ms => 3.375 Sekunden, zumindest meine Zeitmessungen scheinen alle zu stimmen.

Und So wie es aussieht arbeitet Windows in 16ms Zeitrastern, wenn ich das Gleiche auf meinem LINUX System mache, wird sich dann wahrscheinlich Zeigen, dass Linux da "feiner" auflöst, ...
--
Just try it

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von Socke »

corpsman hat geschrieben:
Mo 21. Nov 2022, 09:57
Und So wie es aussieht arbeitet Windows in 16ms Zeitrastern, wenn ich das Gleiche auf meinem LINUX System mache, wird sich dann wahrscheinlich Zeigen, dass Linux da "feiner" auflöst, ...
Zumindest wird das für GetTickCount(64) unter Windows immer wieder kolportiert. Ggf. trifft das auch auf den Thread-Scheduler zu, sodass sobald ein Thread von der CPU genommen wird so lange bis zur nächsten Ausführung warten musst.
Die Ursache könnte also darin liegen, dass unter Windows immer das Betriebssystem für kritische Abschnitte aufgerufen wird, während unter Linux z.B. Futexe zum Einsatz kommen. Delphi hat für sehr kurze exklusive programminterne Sperren die Klasse TMonitor, die einen Spinlock implementiert und es leider noch nicht nach Free Pascal geschafft hat
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Multithreaded Programm verhällt sich auf Windows nicht immer wie erwartet..

Beitrag von corpsman »

Ok, also Ende vom Lied, Windows kriegt das einfach nicht hin..

Bzw. ich sollte schaun, dass ich meine Arbeit anders Organisiere, so dass ich weniger "Synchronisierungspunkte" habe als bisher, denn wenn mein Task ca. 8ms dauert, das warten auf die anderen Threads aber meistens 16ms ist das einfach unsinnig..

=> Eigentlich schade, aber so wie es aussieht macht das OS Paralellität in diesem Fall zu nichte ..
--
Just try it

Antworten