Jackery IFA Fireplace
Mobile

C++ Keine volle Auslastung?

Xtremebergi

Lt. Junior Grade
Registriert
Feb. 2008
Beiträge
312
Hallo zusammen,

mich wundert es, dass ich, selbst wenn ich im main einfach nur eine while(true); reingebe, keine volle Auslastung der CPU erreiche. Es wird auch nicht einfach nur ein Kern voll ausgelastet sondern alle kerne werden so ca. zu 10 - 20 % ausgelastet...

Hä? Kann mir das mal bitte einer erklären? Ich programmiere gerade ein Spiel mit Direct3D und dort hab ich nämlich eine Schleife die ein paar millionen mal pro Sekunde durchlaufen wird. Man kann es im aktuellen Stadium zwar noch nicht "Spiel" nennen aber das Spiel "ruckelt" stark...aber die CPU ist auch da kaum ausgelastet (schön verteilt auf alle kerne). Durch ein-/auskommentieren bin ich mir sicher, dass es die Schleife ist, die so stark bremst...


Warum wird die CPU nicht voll ausgelastet? Wie kann ich das beheben?


Ich benutze Visual Studio Ultimate, Windows 7 Professional und einen i7-2600K.


Danke im Voraus!
Bergi
 
Das liegt daran, dass deine while(true) Schleife lediglich einen Thread forkt und dementsprechend nur auf einer CPU läuft. Der Grund warum alle CPUs Teillast zeigen ist, da du keine Affinität zu einer CPU gesetzt hast, somit wird durch den Scheduler durchaus mal eine andere CPU mit der Aufgabe betraut.

Möchtest du deine Kiste mehr fordern, musst du Threads abspalten und diverse Aufgaben von diversen Threads (#Threads = #Cores) erledigen lassen, dann wird deine Auslastung auch auf 100% steigen.
 
Es wird auch nicht einfach nur ein Kern voll ausgelastet sondern alle kerne werden so ca. zu 10 - 20 % ausgelastet...

Das macht windows manchmal, das aber nur die ausgabe im taskmanger, ein kern ist dann schon ausgelastet

was machst du denn in der schleife, ausgaben, hardwarezugriffe, debugmodus, kann alles bremsen
 
Aha, also kann heutzutage 1 Thread alleine nicht mehr die volle CPU-Leistung in anspruch nehmen? Interessant...ok, gut zu wissen

@Sheeep
nichts aufregendes nur einen großen array durchlaufen, berechnungen und zuweisungen
ist aber auch egal, da es bei einer leeren while-schleife ja dasselbe ist
 
Das konnte ein Thread noch nie. Ein Prozess kann n Threads haben, diese können n Lightweight Processes implementieren, sodass du erst auf diesem Wege eine sehr feingranulare Nutzung deiner Ressources erreichst. Dir muss nur klar sein, wenn du beginnst mit diesen Techniken zu arbeiten, dass du dir sehr schnell Racing Conditions einhandelst, die dein Programm zum Absturz bringen.

Dazu kann ich dir von A. Tannenbaum das Buch "Modern Operating Systems" empfehlen. Dort wird eben diese Thematik gut aufbereitet.

PS: SEHR coole Signatur! :) Kauft keine teure Hardware - optimiert die Software!
 
Ok, vielen Dank an euch, vor allem an GuaRdiaN!
Dann werd ich mich vielleicht mal mehr mit Threads auseinandersetzen.
 
@Xtremebergi
Ein Prozess ohne weitere threads bringt bei while(true); einen kern auf 100% last, wenn der complier das net als dead code rauswirft...

jetzt siehst aber im taskmanager z.T, dass alle kerne etwas ausgelastet sind, aber keine zu 100%....
ich glaub das war dein problem?
das liegt aber am taskmanager.

schau du mal im taskmanager unter prozesse. Da sollte 12 oder 13% für dein programm stehen, was genau 100/8 entspricht und somit einen kern vollständig auslastet...
der taskmanager hat mich in der hinsicht auch schon verwirrt...

wenn du alle kerne willst und nur zuweisungen etc. im array machst (keine abhängigkeiten aus anderen teilen des array), kannst du das ganz einfach mit openmp machen (in einstellungen des projekts aktivieren unter c++):
#pragma omp parallel for
for(int i = 0; i < arraysize; ++i)
{
...
}


GuaRdiaN schrieb:
PS: SEHR coole Signatur! :) Kauft keine teure Hardware - optimiert die Software!

Danke ;)
 
Zuletzt bearbeitet:
Hab das mit OpenMP jetzt probiert..die CPU wird deutlich mehr ausgelastet (~70 - 80 %) aber einen wirklich spürbaren Performance-Schub merke ich nicht...naja, das ist dann aber auch schon wieder ein anderes Thema...

Vielen Dank nochmal!
 
Wenn du dich in der Tat beginnst mit OpenMP zu beschäftigen, kannst du, sofern du ein Spiel schreibst sehr performante Dinge auch auf deine GPU auslagern. Dafür kannst du die SDKs von AMD und nVidia benutzen. Das Zauberwort ist hier OpenCL, die Methoden, die du dafür gebrauchen kannst sind überschaubar. Damit kannst du dann wirklich große Probleme adressieren.

Performanz ist immer so eine Sache in Anwendungen: Grundsätzlich lassen sich einfach User Anwendungen mit dem MVC Prinzip erstellen:

Model / View / Controller. Die View - also die Nutzungsschnittstelle - wird von den Sublayern einfach notified sobald etwas anzuzeigen ist. Somit vergurkst du nur wenig Leistung auf das zeichnen der GUI. Wenn du eine Anwendung schreibst, wo du die GUI z.B. mit 50 Hz zeichnen lässt wirst du sehr schnell Probleme bekommen. Ich kenne die Paradigmen für Spieleentwicklung, allerdings nehme ich stark an, dass du die Engine für die logischen Vorgänge und die Ausgabe klar trennen musst. Vermutlich wird das deine Anwendung träge machen.

Zu der Thread sache: Ein Thread hat "Bauart bedingt" nur eine Affinität. Ein Thread kann durch die Unterteilung in Lightweigt Processes mehrere CPUs auslasten. Allerdings scheint mir das nicht gängige Praixis zu sein. Wobei ich mich auf diese Aussage selbst nicht berufen würde. Klassisch kannst du mit einem Process (also lediglich ein aktiver Thread) nur eine CPU (Core) belasten. Willst du mehr brauchst du mehrere Threads. Allerdings wird es dann schwer, wenn diese auf gemeinsame Ressourcen zugreifen sollen. Wenn du die Strukturen nicht anständig mit Mutexen oder Semaphoren sperrst wirst du dein blaues Wunder erleben. :) Aber wie gesagt -> Ich empfehle bei Interesse den Tannenbaum.
 
Jaja, die Semaphore^^ Den Tannenbaum benutzen wir in der Schule. Was da alles herumgelockt werden muss, ist mir nur zu gut bewusst.

Ja, OpenCL...das hört sich interessant an...ich werde da mal weiter nachforschen :)
 
In DirectX 11 gibts dafür die ComputeShader, also nahtlos integriert.
Semaphore und Mutexe: Wie wärs mit einer CritcalSection, die sollte schneller sein.

@Guardian:
Lightweight-Processes sind doch nichts anderes als ein User-Mode-Scheduler, oder?
Die bringen daher doch gar nix, wenn man Multithreading nicht richtig kenn/anwendet...
 
@Blitzmerker? Was meinst du mit 'Wie wärs mit einer CriticalSection, die sollte schneller sein.' ???

Im ganz groben: Klar ist die Critical Section schneller, weil sie keine Safety-Checks beinhaltet. Aber genau das braucht man doch bei der Parallelen Programmierung. :D Also ich hab keine Ahnung, was du damit sagen willst...
EDIT: P.S. es geht in ALLEN Verfahren der parallelen Programmierung, um die Critical Section. Genauer gesagt, darum, dass niemals mehr als 1 Prozess zu einem Zeitpunkt darin arbeitet! Dir weiteren Punkt sind: Vermeidung von Deadlocks, Lifelocks und Startvation. Sowie die Vermeidung von Busy-Waiting (was im Allgemeinen aber schon durch die Benutzung von Semaphoren, Monitoren, Barriers, etc. ausgeschlossen ist ... außer man nutzt diese Dinge nicht wirklich und baut zusätzlich Busy-Waiting ein)


@TE:
Es gibt noch eine schöne Möglichkeit ohne die ganzen Locks auszukommen: Barrieren!
Nehmen wir mal an, du willst ein Bild berechnen: dann sagst du:
Thread 1: rechne das Viertel oben links, wenn du fertig bis warte an der Barriere
Thread 2: rechne oben rechts, ... s.o. ...
Thread 3: rechne unten links
Thread 4: unten rechts

Das Spannende ist nun: Erst wenn alle 4 fertig sind wird die Barriere zurückgesetzt. Diesen Zeitpunkt kann man nun dazu nutzen, um herauszufinden, wann das Bild fertig ist. Wenn es also fertig ist, kopiert man die 4 Teile zusammen und resettet die Barriere. (Soweit ich mich an meine Vorlesungen erinnern kann, arbeitet OpenCL fast ausschließlich mit Barrieren)
 
Zuletzt bearbeitet:
Blitzmerker schrieb:
Semaphore und Mutexe: Wie wärs mit einer CritcalSection, die sollte schneller sein.

Wenn du den Begriff "critical section" verwendest, als wäre es ein Synchronisationsprimitiv, ist klar daß du von Microsoft Windows redest. Eigentlich ist "critical section" nämlich eher Microsoft-speak für Mutex. Eine "critical section" ist in der normalen, nicht Microsoft-Welt ein Codeabschnitt, der durch einen Synchronisationsprimitiv wie z.B. einen Mutex vor parallelen Zugriffen geschützt werden muß.

Am besten wär's, von OS-spezifischen Konstrukten wegzubleiben und stattdessen etwas wie Intel Threading Building Blocks oder boost::thread einzusetzen. Das lohnt sich allein schon für boost::scoped_lock (besetzt Mutex im Konstruktor, gibt ihn im Destruktor wieder frei).
 
Zurück
Oben