Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

DrthM2001

Alter Hase

  • »DrthM2001« ist der Autor dieses Themas

Beiträge: 721

Wohnort: Karlsruhe

  • Private Nachricht senden

1

20.04.2009, 18:19

Multithread-Programm läuft auf QuadCore langsamer?

Hallo,
ich bin derzeit noch an einem Projekt, dass pro Frame 4 sehr rechenintensive Funktionen rechnen muss. Da bis vor kurzem auf einem DualCore-Laptop entwickelt wurde, hielt ich es für praktisch, die 4 "Hauptfunktionen" zu parallelisieren.
Das geschieht ungefähr so:
Alle Threads warten auf ein Event, das gepulst wird. Jeder Thread hat ein Handle, das als Event dient und signalisiert wenn er fertig ist. Bevor das Signal gepulst wird, werden die Events, dass die Threads fertig sind resettet, danach wird gewartet bis alle fertig sind. Die Threads verweilen solange und warten auf das nächste Startsignal.
Der Code ist eigentlich uninteressant, der vollständigkeit halber:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//Hier werden die Threads gestartet:

void CMultithreading::StartThreads()
{
    ResetEvent(EventTaskFinished[0]);
    ResetEvent(EventTaskFinished[1]);
    ResetEvent(EventTaskFinished[2]);
    ResetEvent(EventTaskFinished[2]);
    PulseEvent(EventStart);
}
//Danach wird hiermit gewaret:

void CMultithreading::WaitForCamMoCap()
{
    WaitForMultipleObjects(4,Game.Multithreading->EventTaskFinished,TRUE,INFINITE);
}

//Die Threadfunktionen sehen alle etwa so aus:

void CamThreadFunktion1()
{
    while(1)
    {
        WaitForSingleObject(Game.Multithreading->EventStart, INFINITE);

        /*Hier: Rechenaufwändige Funktionen, die aber in jedem Thread ähnlich sind*/

        SetEvent(Game.Multithreading->EventTaskFinished[1]);
    }
}


Das funktionierte soweit auch ganz gut, auf dem DualCore Laptop (2*2Ghz) mit etwa 15fps. Ich verkaufte ihn, um einen QuadCore Rechner (4*2.8Ghz,2GB DDR2-800) anzuschaffen, der ja theoretisch aus den mehreren Threads besonders viel Nutzen ziehen sollte.
Jetzt habe ich nur noch mickrige 3 fps und eine CPU Auslastung von maximal 30%! Wenn ich das Multithreading deaktiviere, habe ich auf 3 CPU's geringe Auslastung, auf einer etwa 90%. Treiber sind alle aktuell, ich benutze Vista32bit (wegen angeblich besserem Threadhandling).

Meine Frage:
Warum habe ich keine volle CPU Auslastung, bzw warum ist es so langsam trotz definitiv besserer Hardware?

Um andere Gründe auszuschließen habe ich sämtliche Grafikelemente deaktiviert- nicht dass zB die Grafikkarte der Flaschenhals ist. Ebenfalls habe ich das System durch Benchmarks etc auf Auslastung und Leistung getestet - alles in Ordnung.

Für einen Ratschlag wäre ich sehr dankbar!

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

2

20.04.2009, 20:40

Sind die Rechenaufgaben ungefähr gleich "schwer" bzw. groß? Sicher dass das mit den Events das beste System ist? KA, wie normalerweise Barriere implementiert werden. Vielleicht ist diese Synchronisation einfach das Problem, weil auf eine globale Variable per "lock" asm Befehl zugegriffen wird, was zur Folge hat das er alle Befehle in den Pipes unter Umständen verwirft. Was passiert denn, wenn du das ganze nur auf 2 Threads verteilst? Wenn die Auslastung deutlich höher wird, tippe ich auf extremen Leistungverlust durch die Synchronisation (multithreading nutzen ist einfach, aber sinnvoll einsetzen echt schwer).

EDIT: übrigens ist der Quad bei einzelnen Aufgaben langsamer als der Dual ;). Also nicht unbedingt besser.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

DrthM2001

Alter Hase

  • »DrthM2001« ist der Autor dieses Themas

Beiträge: 721

Wohnort: Karlsruhe

  • Private Nachricht senden

3

20.04.2009, 21:52

Ja die Rechenaufgaben sind etwa gleich groß.
Selbst wenn ich alles in einen Thread packe, ist die Auslastung immer noch so niedrig bei etwa 8-15%, läuft dafür aber noch langsamer :x
Ich muss ergänzen, beim DualCore war es nicht unbedingt schneller, da das Programm inzwischen noch etwas komplexer ist. Dank ein paar Compilereinstellungen bin ich jetzt wieder auf dem Niveau des alten DualCores, wenn auch noch mit weniger Auslastung.

Aber selbst wenn das Threadmanagement ineffizient ist- was es ja scheinbar nicht ist, da ein einziger Thread ebenso schlecht läuft- müsste dann trotz schlechter Performance nicht doch die CPU Auslastung maximal sein, zumindest auf einem Core?

Databyte

Alter Hase

Beiträge: 1 040

Wohnort: Na zu Hause

Beruf: Student (KIT)

  • Private Nachricht senden

4

20.04.2009, 23:38

Ich hab ja nicht so viel Ahnung aber vielleicht kannst du den einzelnen prozessen noch höhere prioritäten geben...
Gerade bei Windows meine ich mich entsinnen zu können, dass das möglich ist und auch was bringt.

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

5

21.04.2009, 11:47

Reden wir denn bei der CPU Auslastung von der Gesamtauslastung? Was sagen denn die einzelnen Kerne so? Hast du schonmal die Wartezeiten und die Rechenzeiten verglichen? Ggf. auch mal einen Profiler drüber gejagt? CodeAnalyst und VCode (so heißt glaube ich das Teil von Intel) sollen ja ganz gut sein.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

DrthM2001

Alter Hase

  • »DrthM2001« ist der Autor dieses Themas

Beiträge: 721

Wohnort: Karlsruhe

  • Private Nachricht senden

6

21.04.2009, 13:35

Die Gesamtauslastung ist etwa gleich der jeweiligen Kernauslastung, also bei den bescheidenen 10%.
Das VC++ interne Performanceanalysetool sagt mir, dass die Wartezeiten ein vielfaches von dem sind, als der Thread läuft :? Hm ich lade gerade den Vtune ( ;) ) Profiler runter und schau mal was der zu sagen hat...

Priorität verändern hat übrigens nicht geholfen, aber danke trotzdem.

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

7

21.04.2009, 17:28

Das mit den Wartezeiten habe ich mir fast gedacht :D. Schonmal mit ner Barrier versucht?
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

DrthM2001

Alter Hase

  • »DrthM2001« ist der Autor dieses Themas

Beiträge: 721

Wohnort: Karlsruhe

  • Private Nachricht senden

8

21.04.2009, 19:11

Die Analysetools haben mich irgendwie nicht weiter gebracht. Nichts was ich nicht schon wusste :?
Was meinst du mit Barrier? Ein Mutex oder wie? Ich kann unter Barrier leider nichts mit WinAPI finden.

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

9

21.04.2009, 19:20

"Thread barriers" ist das Stichwort. Aber nur mal so nebenbei. Warum müssen denn alle Threads so synchronisiert werden? Wäre ein Workloadsystem (workerthreads+taskqueue) nicht praktischer?
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

DrthM2001

Alter Hase

  • »DrthM2001« ist der Autor dieses Themas

Beiträge: 721

Wohnort: Karlsruhe

  • Private Nachricht senden

10

21.04.2009, 19:34

Eigentlich dachte ich, meine Version wäre so etwas wie ein Workload-system. Ein Hauptthread der ein Signal gibt, und die 4 anderen arbeiten drauf los. Wie sollte ich sonst, wenn nicht über Events, von dem Hauptthread kommunizieren?

C-/C++-Quelltext

1
2
3
while(1)
if(ArbeitDa==1)
break;

Das würde den Workthread zwar permanent auslasten, aber in ungutem Leerlauf.
Zu dem Stichwort ThreadBarriers finde ich nur bei OpenMP etwas, was ich jedoch lieber nicht benutzen möchte. Das Windowsinterne Threadmanagment verfügt über nichts dergleichen. Da OpenMP aber ja nur eine Art Wrapper ist, müsste sich das doch auch mit WinAPI lösen lassen.

Werbeanzeige