Nachdem ich erst vor kurzem darum gebeten wurde, eine etwas detailliertere Erklärung zu verschiedenen RAM-Themen zu tippen gibts kurz darauf schon den nächsten Textberg im Alki-Blog dieses Mal aber eher aus der üblichen Eigenmotivation heraus, ständig wiederkehrende Fragen aus dem Forum nicht immer wieder neu erklären zu müssen sondern einfach verlinken zu können. Heute im Angebot: Auslastungsanzeigen.
Es vergeht kein Tag, an dem sich nicht User darüber streiten, welcher Chip denn jetzt wann wo wie ausgelastet ist und was wohl warum jetzt wo der Flaschenhals ist. Diese Thematik, die auf den ersten Blick recht einfach erscheint, bietet dabei aber so viele Fallstricke und Möglichkeiten der Fehlinterpretation, dass leider die meisten Posts die man zu Gesicht bekommt ziemlicher Unsinn sind. Nun kann man den Autoren noch nicht mal besondere Vorwürfe deswegen machen, denn gerade Auslastungsanzeigen gaukeln Nutzern teilweise auch ganz bewusst Dinge vor die geradezu danach schreien, falsch interpretiert zu werden. Denn, und jetzt kommt der übliche Aufmacher des Blogs zum Interesse wecken: Auslastungsanzeigen machen viel aber eines machen sie nicht: Die tatsächliche Auslastung eines Chips anzeigen. Warum das so ist und was diese Anzeigen tatsächlich tun folgt jetzt.
Um zu verstehen, wie solche Anzeigen funktionieren und was sie tun, sowie wo die beiden größten Fallen zu finden sind, muss wie so häufig etwas ausgeholt werden. Fangen wir doch mit dem häufigsten aber auch am einfachsten zu verstehenden Fehler an: Kumulierende Auslastungen.
Viele Kerne, eine Zahl
Viele Tools einschließlich des Windows Task-Managers (in seiner Werkseinstellung) zeigen die Auslastung einer CPU als einfachen Prozentwert an. Nun gehen wir vorerst mal davon aus, dass die Auslastung tatsächlich das ist, was die Leute sich darunter vorstellen, nämlich wie beschäftigt die CPU gerade ist. Für dieses Beispiel funktioniert diese (falsche) Annahme noch. Wie bekannt sein sollte, bestehen moderne CPUs aus mehreren Kernen, in den aktuell ausgebrochenen Kernkriegen kann ein geneigter Anwender mit dem kürzlich vorgestellten Threadripper 2990WX ganze 32 Kerne in einer CPU kaufen wenn er das möchte. Zusätzlich können viele CPUs wie auch der genannte mehrere Threads gleichzeitig auf einem Kern ausführen (Simultaneous Multithreading), was für das Betriebssystem durch virtuelle Kerne realisiert wird. Ein 2990WX wird also im Windows als 64-Kern CPU geführt (32 reale und 32 virtuelle Kerne). Nun stellen wir uns vor, eine Anwendung benutzt 4 Threads und kann diese auch voll auslasten kann aber mit mehr Threads nichts anfangen. Auf einer solchen Monster-CPU hätte das eine kumulierte Auslastung von grade mal 6% zur Folge die CPU ist aber an der Stelle der Flaschenhals, obwohl sie so gut wie nichts zu tun hat.
Um es für Normalsterbliche realitätsnaher zu machen: Ein Ryzen 2700X (8 Kerne, 16 Threads), der ein Spiel berechnen soll das 6 Threads auslasten kann (und damit schon recht gut optimiert ist!) hätte im CPU-Limit eine angezeigte Auslastung von im günstigsten Fall nur 30-40%! Wenn nur ein einzelner Thread der limitierende ist und die anderen 5 genutzten auf diesen warten müssen wird der Wert noch kleiner. Dieser angezeigte Wert ist also für sich gesehen absolut nicht aussagekräftig in diesem Zusammenhang! Was an der Stelle noch helfen kann ist, sich die Einzelauslastungen der einzelnen Threads anzeigen zu lassen, was die allermeisten Tools können. Sobald hier ein Thread über 80-90% Belastung geht ist davon auszugehen, dass die CPU anfängt zu limitieren (warum es keine 100 sein müssen und warum man hier am besten gar nicht drauf achtet später mehr).
Was ist eigentlich "Auslastung"?
Alles was bis jetzt geschrieben wurde dürfte für Leute, die sich für diese Thematik interessieren, normalerweise noch kein völliges Neuland sein. Was nun kommt hat da schon größere Chancen: Was Tools als Auslastung anzeigen hat mit der tatsächlichen Auslastung eines Chips kaum etwas zu tun denn weder der Chip noch das Tool wissen, wie ausgelastet der Chip tatsächlich gerade ist woher auch? Es gibt keine Routinen in einem Chip die kontrollieren könnten wie die Arbeitsbelastung (wie auch immer man diese definieren würde) gerade wirklich ausfällt. So etwas wären völlig sinnlos vergeudete Transistoren. Die ganzen Betriebsparameter, die heutzutage in Echtzeit dynamisch an die aktuelle Situation angepasst werden (Boottaktraten usw.), werden NICHT über Auslastungen geregelt da diese nunmal nicht bekannt sind. Die Regelung erfolgt über eine komplizierte Sensorik für Temperatur, Leistungsaufnahme und genutzten Untereinheiten der CPU.
Was genau ist denn also jetzt dieser ominöse Prozentwert der Auslastung? Dazu ein sehr vereinfachtes Bild wie eine Abfolge von Rechenaufgaben so erledigt wird. Der Anwender möchte eine Aufgabe X erledigt haben, beispielsweise konvertiere mir alle Bilder in diesem Ordner von BMP in JPG. Ein entsprechendes Programm setzt die Nutzereingaben in Befehle für das Betriebssystem um. Das Betriebssystem besitzt nun einen sogenannten Scheduler eine Routine die dafür da ist, Aufgaben in kleine für die CPU verständliche Häppchen zu zerhacken und diese möglichst sinnvoll an die CPU weiterzugeben. Dieser Scheduler kann zum Beispiel auch virtuelle von echten Kernen unterscheiden und entsprechend sinnvoll Aufgaben verteilen. Was er dagegen nicht kann ist, eigenständig mehrere Threads für eine Aufgabe zu generieren, bedeutet wenn das Bildprogramm nur 4 Threads erstellt und damit immer 4 Bilder gleichzeitig umwandelt kann der Scheduler diese 4 Threads sinnvoll auf vier echte Kerne verteilen aber keine 8 Threads daraus machen.
Nun gibt es eine (den Umständen entsprechend variable) Anzahl an Aufgaben pro Sekunde, die die CPU, genauer gesagt jeder einzelne Thread, annehmen kann, die sie sozusagen in ihre To-Do-Liste aufnimmt und dann nach und nach abarbeitet. Das, was der Scheduler als Auslastung von Threads in Prozent ausgibt (das ist rein softwarebasiert!) ist die Anzahl der an den Thread gegebenen Aufgabenpakete pro maximal möglicher Anzahl an Aufgabenpaketen.
Angenommen, ein Thread könnte 1000 Aufgaben pro Millisekunde annehmen und der Scheduler hat 500 Aufgaben für ihn bereit läge die aktuelle Auslastung dieses Threads bei 50%. Hat der Scheduler 1000 Aufgaben bereit wären es 100% - und die wären es auch, wenn der Scheduler 893456823 Aufgaben bereit hat das ist dann das berühmte CPU-Limit: Es sind schneller Aufgaben da als sie abgearbeitet werden können.
Nun bemerkt der geneigte Leser vielleicht, dass ich immer nur von Aufgaben rede und keine spezielleren Berechnungen erwähne. Das ist absichtlich so, denn für die CPU und auch für die Auslastung ist es völlig egal, ob ich irgendwelche wahnsinnig komplexen Aufgaben berechnen lassen will oder ob ich nur 1+1-1+1-1+1-1+1- berechnen lassen will. Die Komplexität spielt zunächst keine Rolle, die CPU muss jede Aufgabe die kommt gleich behandeln und abarbeiten (Fetch+Decode). Natürlich geht das bei einer +1-Aufgabe nach dem decodieren in der CPU sehr viel schneller als bei einer komplizierten Aufgabe die viele Taktzyklen erfordert. So lange der Scheduler aber auch entsprechend schneller die To-Do-Liste nachfüllen kann bleibt die Auslastung des Threads bei 100%.
Und das ist einer der unbekannteren Zusammenhänge: 100% ist nicht gleich 100%. Denn die Auslastung sagt nur, wie viele Befehle die CPU gerade in ihrer To-Do-Liste hat, nicht welche das sind oder wie kompliziert sie sind. Vollauslastung bedeutet nur CPU kann keine weiteren Aufgaben annehmen, es bedeutet NICHT CPU arbeitet sehr hart / am Limit! Experimentierfreudigeren Naturen ist vielleicht schon einmal aufgefallen, dass verschiedene Tools und Benchmarks allesamt 100% Auslastung erzeugen, dabei aber völlig verschiedene Stromverbräuche und Temperaturen provozieren. Die 100% eines Cinebench-Testlaufes erzeugen beispielsweise viel weniger Verbrauch und Wärme als die 100% eines Prime95-Tests. Dies liegt genau an der Komplexität der Aufgaben. Das Rendering des Cinebenches besteht aus extrem vielen parallel ausführbaren aber vergleichsweise einfachen Rechenoperationen. Die To-Do-Liste ist immer prall gefüllt, die Recheneinheiten hinter dem/den Decodierer(n) sind aber nicht so extrem gefordert. Prime95 dagegen berechnet für eine CPU sehr komplexe Fourier-Transformationen. Auch hier ist die To-Do-Liste immer voll da man solche FFTs sehr schnell generieren kann, die Berechnung ist aber sehr viel aufwendiger und resultiert (besonders wenn noch spezielle, in dem Fall sehr viel schnellere Einheiten wie AVX genutzt werden) daher in bedeutend höheren Stromverbräuchen und Temperaturen. An der gezeigten Auslastung ändert das alles nichts, denn wie gesagt dieser Wert hat mit dem, was die CPU tatsächlich berechnen muss und wie beschäftigt sie ist, nichts zu tun.
Was würde passieren, wenn...
An der Stelle mal ein kleiner Fun-Fact am Rande da es hier gut passt: Die allermeisten Transistoren einer modernen CPU oder GPU machen die meiste Zeit unter Vollast genau: Nichts. Nur ein sehr kleiner Teil der Transistoren ist in einer CPU tatsächlich zeitgleich am schalten, selbst unter großer Last. Würden alle vorhandenen Transistoren gleichzeitig schalten würde die CPU spontan verdampfen. Was passiert, wenn deutlich mehr Transistoren als üblich gleichzeitig schalten müssen wird am Beispiel der AVX-Einheiten deutlich die genau auf diesem Prinzip funktionieren (viele gleichartige Befehle/Vektoroperationen geordnet in einem Schaltschritt gleichzeitig ausführen): Die Leistungsaufnahme und Abwärme steigt so massiv an, dass die Taktrate deutlich zurückgenommen werden muss um das auszugleichen.
Limitierungen finden
Wie finde ich aber nun heraus ob die CPU beispielsweise in meinem Spiel limitiert wo deren Auslastungsanzeigen für diesen Zweck ziemlich nutzlos sind? Es klingt vielleicht nach dem ganzen Text seltsam aber: An der Auslastung der GPU.
Warum ist dieser Wert denn nun aussagekräftiger oder macht der etwa was anderes? Nein, macht er nicht. Die Auslastung der GPU ist genau dasselbe: Anzahl der Aufgaben pro Anzahl der maximal möglichen Aufgaben. ABER: Die Unterschiede in den möglichen Komplexitäten der Aufgaben sind sehr viel kleiner. Die oben betrachteten CPUs sind extrem vielseitige Chips die alles berechnen können was gewünscht ist bzw. frei programmierbar sind (Turing-Vollständig). Von sehr komplexen FFTs bis einfachem 1+1 ist alles kein Problem. Die Kerne in GPUs sind hier sehr viel einfacher gestrickt. Diese können nur sehr bestimmte, vergleichsweise einfache Aufgaben erledigen, diese aber massiv parallelisiert. Wie vielleicht bekannt ist findet man in modernen GPUs Tausende an Shadern was hier sozusagen die Kerne sind. Da die Aufgabenpäckchen hier allesamt sehr einfach sind und wir eine extrem hohe Zahl von Ausführungseinheiten haben korreliert die Anzahl an anstehenden Aufgaben sehr gut mit der Arbeitsbelastung der Ausführungseinheiten. Wenn eine GPU mit 80% Auslastung werkelt kann man daher recht sicher davon ausgehen, dass auch tatsächlich gerade grob 75-85% der Ausführungseinheiten tatsächlich gerade was zu tun haben. Aus dem Grund ist auch das 100% von Spiel A gut vergleichbar mit dem 100% des Spiels B was Abwärme und Verbrauch angeht. Auch hier gibts noch kleinere Unterschiede da es noch eine Rolle spielt, ob ein Shader gerade Dreiecke zeichnen soll oder einen Pixelshader ausführt oder eine Physikberechnung übernimmt, alleine durch die massive Anzahl an Einheiten wird das im Mittel aber sehr gut ausgeglichen zumindest wenn man Spiele vergleicht die all diese Funktionen auch benutzen (ein 20 Jahre alter Klassiker der nur Dreiecke malt und Texturen draufpappt hat kaum eine Chance mehr, eine modere GPU wirklich zu belasten). Hier kann zwar mit ein paar geschickten Tricks auch mit Gewalt eine höhere tatsächliche Last erzielt werden indem man die Aufgaben für die Shader so aufwendig wie möglich gestaltet (der Furmark macht das), der Unterschied ist aber deutlich geringer als man es bei CPUs kennt.
Zumindest für das auffinden von Flaschenhälsen bei Spielen ists also dann doch nicht allzu schwierig. Ist die Auslastung der Grafikkarte dauerhaft über 90% limitiert die Grafikkarte, liegt sie darunter limitiert etwas anderes zumeist die CPU (hier aber etwas vorsichtig sein, auch ein voller vRAM oder aktiviertes vSync kann eine geringe GPU-Auslastung erzeugen).
Die Sache mit dem RAM
Ein Kapitel möchte ich in dem Zusammenhang auch noch aufmachen: Auslastungen von flüchtigen Speichern. Bereits intuitiv dürfte den meisten Lesern klar sein, dass eine Auslastung des RAMs nichts mit seiner aktuellen Arbeitsbelastung zu tun hat sondern seinen Füllstand anzeigen soll. Wenn man darüber nachdenkt wird einem schnell klar, dass das Wort Auslastung bei Chips und bei Speicher also völlig verschiedene Dinge beschreibt. Und auch hier gibts einige Fallen, in die ständig getappt wird in manche sogar so oft und so unbelehrbar, dass die (Windows-)Definition von RAM-Auslastung über die Jahre geändert wurde!
Ein normaler Mensch würde denken: Wenn mein RAM eine Auslastung von 40% hat dann ist er 40% voll und 60% leer.
Denkste.
So war es bis vor vielen Jahren tatsächlich und so wäre auch die sinnvolle Definition. Beim vRAM ist es auch bis heute (noch) üblich es so anzugeben. Ich merke ein noch an, da sich das vermutlich genauso ändern wird wenn die Nutzung des Speichers besser wird und mehr Leute auf ihre Auslastungsanzeigen schauen. Aber zurück zum normalen RAM.
Hier war es in frühen Tagen wie gesagt tatsächlich so, dass der echte Füllstand des RAMs als Auslastung angezeigt werden konnte. Nun sind die allermeisten Leute da draußen der Meinung, dass es sehr sinnvoll ist, noch freien RAM übrig zu haben und ein Programm möglichst wenig RAM verbrauchen sollte (gibs zu, du glaubst das auch, oder?). Blöderweise ist genau das Gegenteil der Fall. Ich meine damit natürlich nicht schlecht programmierte Software die RAM vollklatscht ohne einen Nutzen davon zu haben aber es ist wenn genügend RAM da ist nunmal sehr sinnvoll, alles mögliche reinzuladen das man vielleicht nutzen könnte und falls mans doch nicht braucht oder der Platz anders genutzt werden soll es eben wieder fix zu löschen was RAM in einer Millisekunde erledigt. Denn: Leerer RAM ist ungenutzter RAM ist unnötiger RAM ist verschenkte Leistung! Arbeitsspeicher ist eben nicht dann gut genutzt wenn er möglichst frei ist sondern wenn er dynamisch möglichst voll ist! Hier bitte ganz bewusst unterscheiden zwischen voll und zu klein. Das ist was völlig unterschiedliches!
Das alles weiß eigentlich jeder bessere Programmierer da draußen seit Jahrzehnten natürlich auch die von Microsoft. Also hat man nach und nach Ende der 90er Jahre damit begonnen, die immer größer werdenden RAM-Mengen in PCs auch dynamisch sinnvoll zu nutzen. Beispiel: Wurde eine Datei von Windows98 von einem Datenträge A auf einen Datenträger B kopiert hat Windows das nicht mehr A --> B gemacht (wo die Datenträger sich gegenseitig ausbremsen) sondern den Ram als Puffer genutzt wenn möglich, sprich A --> RAM --> B. Zusätzlich hat Windows nach abgeschlossenem Kopiervorgang die Datei im Ram einfach drin gelassen wenn man den Ram nicht sonstwie gebraucht hat für den Fall, dass der User die Datei vielleicht noch auf den Datenträger C kopieren will war das dann bedeutend schneller da sofort aus dem RAM gelesen werden konnte. Eine sehr sinnvolle Nutzung von sonst nicht benötigtem RAM, oder? Blöderweise zeigte die Auslastungsanzeige des RAMs dadurch aber schnell Werte nahe der 100%, denn Windows begann, den vorhandenen RAM tatsächlich sinnvoll zu nutzen und Daten die vielleicht nochmal gebraucht wurden einfach liegen zu lassen. Das war kein Problem, denn sobald ein anderes Programm mehr RAM anforderte wurden die alten Daten rausgeworfen und alles war wieder gut. Und jetzt darf geraten werden, wie die breite Masse darauf reagiert hat, dass ein neues Betriebssystem immer anzeigt der RAM ist voll. Und nach einer sauteuren Aufrüstung von 32 auf 64 MiB RAM war er danach ja schon wieder voll! Der Shitstorm war wegen des damaligen Standes des Internets zwar überschaubar, dennoch war das Geschrei aber groß genug dass Microsoft reagieren musste. Noch heute gibt es unzählige User die mit irgendwelchen Schwachsinnstools ihren RAM freischaufeln wollen und das schöne Caching von Windows damit zerschießen. Die Tools machen dabei nichts als Windows zu sagen gib mir allen RAM den du hast. Windows löscht alle nicht zwingend benötigten Daten im RAM, weist den ganzen RAM dem Tool zu und das Tool sagt dann ok, beende die Zuweisung und der RAM ist leer (und alles was gecacht war muss erneut nachgeladen werden Glückwunsch).
Natürlich wurde bis heute an der sinnvollen RAM-Nutzung nichts geändert. Auch Windows XP, 7, 8, 10 macht dasselbe wie Win98 damals und lässt alte Daten im RAM liegen bis man den Speicher sonstwie braucht. Nur: Man zeigt es dem Nutzer einfach nicht mehr an denn was er nicht weiß macht ihn nicht heiß. Etwas versteckt gibt es die Zahlen noch im Task-Manager zu sehen. Windows 7 unterschied noch von Insgesamt, Verfügbar, Im Cache und frei wobei nur das frei tatsächlich leer bedeutet und hier steht in aller Regel wenn der PC schon etwas länger an ist eine Null. Windows10 nennts noch etwas kryptischer available, committed, cached usw. aber alle haben sie gemeinsam: Der RAM wird komplett vollgeklatscht und genutzt bis zum letzten MB. Die schönen bunten Graphen zeigen das natürlich nicht an, hier wird der ich nenne es mal Datencache einfach weggelassen damit sich der Pöbel nicht darüber aufregt dass beispielsweise Win10 64GiB RAM belegt wenn es sie hat und man viele Daten verschiebt/kopiert.
Diese sinnvolle Speichernutzung hat auch das eine oder andere Entwicklerstudio bereits vor einigen Jahren bei Spielen versucht einzusetzen und es wieder verworfen. Ein Beispiel dafür war das Spiel Lords of the Fallen. Problemlos auf Grafikkarten mit 1,5 GiB vRAM spielbar, belegte das Spiel auch auf einer 12 GB-(damals AMD FirePro-Server-)Grafikkarte den vollen Grafikspeicher. Der Hintergrund: Das Spiel lud an Stellen wo rechentechnisch Zeit dafür war einfach die nachfolgenden Level des Spiels schon mal in den vRAM bis dieser voll war. Resultat war, dass auf Grafikkarten mit viel Speicher die Ladezeiten von einem Level zum nächsten bedeutend kürzer ausfielen. Super Sache, oder? Nein, leider nicht. Da die breite Masse diesen Hintergrund nicht versteht und mittlerweile das Internet eine Märchenverbreitungsmaschine sondergleichen geworden ist haben folgende Spiele das Feature nicht mehr. Der Imageschaden durch Tausende an rumschreienden das schei*-Spiel braucht drölfzig GB vRAM!!!!11eins und darauf folgende sinkende Verkaufszahlen weil andere es auch noch glauben ist deutlich größer als der Vorteil, neue Level schneller laden zu können. Der Michel zu Hause starrt halt lieber länger auf den Ladebalken, so lange er wenigstens sicher ist, dass die Hälfte seines vRAMs auch schön (unsinnig) leer bleibt.
So, Standardkundschaft meines Blogs kennts ja schon, Glückwunsch zum Durchhalten bis zum Ende des nunmehr 40. Blogs (auweia ), Fragen, Anregungen, Kommentare gerne darunter oder per PN.
Es vergeht kein Tag, an dem sich nicht User darüber streiten, welcher Chip denn jetzt wann wo wie ausgelastet ist und was wohl warum jetzt wo der Flaschenhals ist. Diese Thematik, die auf den ersten Blick recht einfach erscheint, bietet dabei aber so viele Fallstricke und Möglichkeiten der Fehlinterpretation, dass leider die meisten Posts die man zu Gesicht bekommt ziemlicher Unsinn sind. Nun kann man den Autoren noch nicht mal besondere Vorwürfe deswegen machen, denn gerade Auslastungsanzeigen gaukeln Nutzern teilweise auch ganz bewusst Dinge vor die geradezu danach schreien, falsch interpretiert zu werden. Denn, und jetzt kommt der übliche Aufmacher des Blogs zum Interesse wecken: Auslastungsanzeigen machen viel aber eines machen sie nicht: Die tatsächliche Auslastung eines Chips anzeigen. Warum das so ist und was diese Anzeigen tatsächlich tun folgt jetzt.
Um zu verstehen, wie solche Anzeigen funktionieren und was sie tun, sowie wo die beiden größten Fallen zu finden sind, muss wie so häufig etwas ausgeholt werden. Fangen wir doch mit dem häufigsten aber auch am einfachsten zu verstehenden Fehler an: Kumulierende Auslastungen.
Viele Kerne, eine Zahl
Viele Tools einschließlich des Windows Task-Managers (in seiner Werkseinstellung) zeigen die Auslastung einer CPU als einfachen Prozentwert an. Nun gehen wir vorerst mal davon aus, dass die Auslastung tatsächlich das ist, was die Leute sich darunter vorstellen, nämlich wie beschäftigt die CPU gerade ist. Für dieses Beispiel funktioniert diese (falsche) Annahme noch. Wie bekannt sein sollte, bestehen moderne CPUs aus mehreren Kernen, in den aktuell ausgebrochenen Kernkriegen kann ein geneigter Anwender mit dem kürzlich vorgestellten Threadripper 2990WX ganze 32 Kerne in einer CPU kaufen wenn er das möchte. Zusätzlich können viele CPUs wie auch der genannte mehrere Threads gleichzeitig auf einem Kern ausführen (Simultaneous Multithreading), was für das Betriebssystem durch virtuelle Kerne realisiert wird. Ein 2990WX wird also im Windows als 64-Kern CPU geführt (32 reale und 32 virtuelle Kerne). Nun stellen wir uns vor, eine Anwendung benutzt 4 Threads und kann diese auch voll auslasten kann aber mit mehr Threads nichts anfangen. Auf einer solchen Monster-CPU hätte das eine kumulierte Auslastung von grade mal 6% zur Folge die CPU ist aber an der Stelle der Flaschenhals, obwohl sie so gut wie nichts zu tun hat.
Um es für Normalsterbliche realitätsnaher zu machen: Ein Ryzen 2700X (8 Kerne, 16 Threads), der ein Spiel berechnen soll das 6 Threads auslasten kann (und damit schon recht gut optimiert ist!) hätte im CPU-Limit eine angezeigte Auslastung von im günstigsten Fall nur 30-40%! Wenn nur ein einzelner Thread der limitierende ist und die anderen 5 genutzten auf diesen warten müssen wird der Wert noch kleiner. Dieser angezeigte Wert ist also für sich gesehen absolut nicht aussagekräftig in diesem Zusammenhang! Was an der Stelle noch helfen kann ist, sich die Einzelauslastungen der einzelnen Threads anzeigen zu lassen, was die allermeisten Tools können. Sobald hier ein Thread über 80-90% Belastung geht ist davon auszugehen, dass die CPU anfängt zu limitieren (warum es keine 100 sein müssen und warum man hier am besten gar nicht drauf achtet später mehr).
Was ist eigentlich "Auslastung"?
Alles was bis jetzt geschrieben wurde dürfte für Leute, die sich für diese Thematik interessieren, normalerweise noch kein völliges Neuland sein. Was nun kommt hat da schon größere Chancen: Was Tools als Auslastung anzeigen hat mit der tatsächlichen Auslastung eines Chips kaum etwas zu tun denn weder der Chip noch das Tool wissen, wie ausgelastet der Chip tatsächlich gerade ist woher auch? Es gibt keine Routinen in einem Chip die kontrollieren könnten wie die Arbeitsbelastung (wie auch immer man diese definieren würde) gerade wirklich ausfällt. So etwas wären völlig sinnlos vergeudete Transistoren. Die ganzen Betriebsparameter, die heutzutage in Echtzeit dynamisch an die aktuelle Situation angepasst werden (Boottaktraten usw.), werden NICHT über Auslastungen geregelt da diese nunmal nicht bekannt sind. Die Regelung erfolgt über eine komplizierte Sensorik für Temperatur, Leistungsaufnahme und genutzten Untereinheiten der CPU.
Was genau ist denn also jetzt dieser ominöse Prozentwert der Auslastung? Dazu ein sehr vereinfachtes Bild wie eine Abfolge von Rechenaufgaben so erledigt wird. Der Anwender möchte eine Aufgabe X erledigt haben, beispielsweise konvertiere mir alle Bilder in diesem Ordner von BMP in JPG. Ein entsprechendes Programm setzt die Nutzereingaben in Befehle für das Betriebssystem um. Das Betriebssystem besitzt nun einen sogenannten Scheduler eine Routine die dafür da ist, Aufgaben in kleine für die CPU verständliche Häppchen zu zerhacken und diese möglichst sinnvoll an die CPU weiterzugeben. Dieser Scheduler kann zum Beispiel auch virtuelle von echten Kernen unterscheiden und entsprechend sinnvoll Aufgaben verteilen. Was er dagegen nicht kann ist, eigenständig mehrere Threads für eine Aufgabe zu generieren, bedeutet wenn das Bildprogramm nur 4 Threads erstellt und damit immer 4 Bilder gleichzeitig umwandelt kann der Scheduler diese 4 Threads sinnvoll auf vier echte Kerne verteilen aber keine 8 Threads daraus machen.
Nun gibt es eine (den Umständen entsprechend variable) Anzahl an Aufgaben pro Sekunde, die die CPU, genauer gesagt jeder einzelne Thread, annehmen kann, die sie sozusagen in ihre To-Do-Liste aufnimmt und dann nach und nach abarbeitet. Das, was der Scheduler als Auslastung von Threads in Prozent ausgibt (das ist rein softwarebasiert!) ist die Anzahl der an den Thread gegebenen Aufgabenpakete pro maximal möglicher Anzahl an Aufgabenpaketen.
Angenommen, ein Thread könnte 1000 Aufgaben pro Millisekunde annehmen und der Scheduler hat 500 Aufgaben für ihn bereit läge die aktuelle Auslastung dieses Threads bei 50%. Hat der Scheduler 1000 Aufgaben bereit wären es 100% - und die wären es auch, wenn der Scheduler 893456823 Aufgaben bereit hat das ist dann das berühmte CPU-Limit: Es sind schneller Aufgaben da als sie abgearbeitet werden können.
Nun bemerkt der geneigte Leser vielleicht, dass ich immer nur von Aufgaben rede und keine spezielleren Berechnungen erwähne. Das ist absichtlich so, denn für die CPU und auch für die Auslastung ist es völlig egal, ob ich irgendwelche wahnsinnig komplexen Aufgaben berechnen lassen will oder ob ich nur 1+1-1+1-1+1-1+1- berechnen lassen will. Die Komplexität spielt zunächst keine Rolle, die CPU muss jede Aufgabe die kommt gleich behandeln und abarbeiten (Fetch+Decode). Natürlich geht das bei einer +1-Aufgabe nach dem decodieren in der CPU sehr viel schneller als bei einer komplizierten Aufgabe die viele Taktzyklen erfordert. So lange der Scheduler aber auch entsprechend schneller die To-Do-Liste nachfüllen kann bleibt die Auslastung des Threads bei 100%.
Und das ist einer der unbekannteren Zusammenhänge: 100% ist nicht gleich 100%. Denn die Auslastung sagt nur, wie viele Befehle die CPU gerade in ihrer To-Do-Liste hat, nicht welche das sind oder wie kompliziert sie sind. Vollauslastung bedeutet nur CPU kann keine weiteren Aufgaben annehmen, es bedeutet NICHT CPU arbeitet sehr hart / am Limit! Experimentierfreudigeren Naturen ist vielleicht schon einmal aufgefallen, dass verschiedene Tools und Benchmarks allesamt 100% Auslastung erzeugen, dabei aber völlig verschiedene Stromverbräuche und Temperaturen provozieren. Die 100% eines Cinebench-Testlaufes erzeugen beispielsweise viel weniger Verbrauch und Wärme als die 100% eines Prime95-Tests. Dies liegt genau an der Komplexität der Aufgaben. Das Rendering des Cinebenches besteht aus extrem vielen parallel ausführbaren aber vergleichsweise einfachen Rechenoperationen. Die To-Do-Liste ist immer prall gefüllt, die Recheneinheiten hinter dem/den Decodierer(n) sind aber nicht so extrem gefordert. Prime95 dagegen berechnet für eine CPU sehr komplexe Fourier-Transformationen. Auch hier ist die To-Do-Liste immer voll da man solche FFTs sehr schnell generieren kann, die Berechnung ist aber sehr viel aufwendiger und resultiert (besonders wenn noch spezielle, in dem Fall sehr viel schnellere Einheiten wie AVX genutzt werden) daher in bedeutend höheren Stromverbräuchen und Temperaturen. An der gezeigten Auslastung ändert das alles nichts, denn wie gesagt dieser Wert hat mit dem, was die CPU tatsächlich berechnen muss und wie beschäftigt sie ist, nichts zu tun.
Was würde passieren, wenn...
An der Stelle mal ein kleiner Fun-Fact am Rande da es hier gut passt: Die allermeisten Transistoren einer modernen CPU oder GPU machen die meiste Zeit unter Vollast genau: Nichts. Nur ein sehr kleiner Teil der Transistoren ist in einer CPU tatsächlich zeitgleich am schalten, selbst unter großer Last. Würden alle vorhandenen Transistoren gleichzeitig schalten würde die CPU spontan verdampfen. Was passiert, wenn deutlich mehr Transistoren als üblich gleichzeitig schalten müssen wird am Beispiel der AVX-Einheiten deutlich die genau auf diesem Prinzip funktionieren (viele gleichartige Befehle/Vektoroperationen geordnet in einem Schaltschritt gleichzeitig ausführen): Die Leistungsaufnahme und Abwärme steigt so massiv an, dass die Taktrate deutlich zurückgenommen werden muss um das auszugleichen.
Limitierungen finden
Wie finde ich aber nun heraus ob die CPU beispielsweise in meinem Spiel limitiert wo deren Auslastungsanzeigen für diesen Zweck ziemlich nutzlos sind? Es klingt vielleicht nach dem ganzen Text seltsam aber: An der Auslastung der GPU.
Warum ist dieser Wert denn nun aussagekräftiger oder macht der etwa was anderes? Nein, macht er nicht. Die Auslastung der GPU ist genau dasselbe: Anzahl der Aufgaben pro Anzahl der maximal möglichen Aufgaben. ABER: Die Unterschiede in den möglichen Komplexitäten der Aufgaben sind sehr viel kleiner. Die oben betrachteten CPUs sind extrem vielseitige Chips die alles berechnen können was gewünscht ist bzw. frei programmierbar sind (Turing-Vollständig). Von sehr komplexen FFTs bis einfachem 1+1 ist alles kein Problem. Die Kerne in GPUs sind hier sehr viel einfacher gestrickt. Diese können nur sehr bestimmte, vergleichsweise einfache Aufgaben erledigen, diese aber massiv parallelisiert. Wie vielleicht bekannt ist findet man in modernen GPUs Tausende an Shadern was hier sozusagen die Kerne sind. Da die Aufgabenpäckchen hier allesamt sehr einfach sind und wir eine extrem hohe Zahl von Ausführungseinheiten haben korreliert die Anzahl an anstehenden Aufgaben sehr gut mit der Arbeitsbelastung der Ausführungseinheiten. Wenn eine GPU mit 80% Auslastung werkelt kann man daher recht sicher davon ausgehen, dass auch tatsächlich gerade grob 75-85% der Ausführungseinheiten tatsächlich gerade was zu tun haben. Aus dem Grund ist auch das 100% von Spiel A gut vergleichbar mit dem 100% des Spiels B was Abwärme und Verbrauch angeht. Auch hier gibts noch kleinere Unterschiede da es noch eine Rolle spielt, ob ein Shader gerade Dreiecke zeichnen soll oder einen Pixelshader ausführt oder eine Physikberechnung übernimmt, alleine durch die massive Anzahl an Einheiten wird das im Mittel aber sehr gut ausgeglichen zumindest wenn man Spiele vergleicht die all diese Funktionen auch benutzen (ein 20 Jahre alter Klassiker der nur Dreiecke malt und Texturen draufpappt hat kaum eine Chance mehr, eine modere GPU wirklich zu belasten). Hier kann zwar mit ein paar geschickten Tricks auch mit Gewalt eine höhere tatsächliche Last erzielt werden indem man die Aufgaben für die Shader so aufwendig wie möglich gestaltet (der Furmark macht das), der Unterschied ist aber deutlich geringer als man es bei CPUs kennt.
Zumindest für das auffinden von Flaschenhälsen bei Spielen ists also dann doch nicht allzu schwierig. Ist die Auslastung der Grafikkarte dauerhaft über 90% limitiert die Grafikkarte, liegt sie darunter limitiert etwas anderes zumeist die CPU (hier aber etwas vorsichtig sein, auch ein voller vRAM oder aktiviertes vSync kann eine geringe GPU-Auslastung erzeugen).
Die Sache mit dem RAM
Ein Kapitel möchte ich in dem Zusammenhang auch noch aufmachen: Auslastungen von flüchtigen Speichern. Bereits intuitiv dürfte den meisten Lesern klar sein, dass eine Auslastung des RAMs nichts mit seiner aktuellen Arbeitsbelastung zu tun hat sondern seinen Füllstand anzeigen soll. Wenn man darüber nachdenkt wird einem schnell klar, dass das Wort Auslastung bei Chips und bei Speicher also völlig verschiedene Dinge beschreibt. Und auch hier gibts einige Fallen, in die ständig getappt wird in manche sogar so oft und so unbelehrbar, dass die (Windows-)Definition von RAM-Auslastung über die Jahre geändert wurde!
Ein normaler Mensch würde denken: Wenn mein RAM eine Auslastung von 40% hat dann ist er 40% voll und 60% leer.
Denkste.
So war es bis vor vielen Jahren tatsächlich und so wäre auch die sinnvolle Definition. Beim vRAM ist es auch bis heute (noch) üblich es so anzugeben. Ich merke ein noch an, da sich das vermutlich genauso ändern wird wenn die Nutzung des Speichers besser wird und mehr Leute auf ihre Auslastungsanzeigen schauen. Aber zurück zum normalen RAM.
Hier war es in frühen Tagen wie gesagt tatsächlich so, dass der echte Füllstand des RAMs als Auslastung angezeigt werden konnte. Nun sind die allermeisten Leute da draußen der Meinung, dass es sehr sinnvoll ist, noch freien RAM übrig zu haben und ein Programm möglichst wenig RAM verbrauchen sollte (gibs zu, du glaubst das auch, oder?). Blöderweise ist genau das Gegenteil der Fall. Ich meine damit natürlich nicht schlecht programmierte Software die RAM vollklatscht ohne einen Nutzen davon zu haben aber es ist wenn genügend RAM da ist nunmal sehr sinnvoll, alles mögliche reinzuladen das man vielleicht nutzen könnte und falls mans doch nicht braucht oder der Platz anders genutzt werden soll es eben wieder fix zu löschen was RAM in einer Millisekunde erledigt. Denn: Leerer RAM ist ungenutzter RAM ist unnötiger RAM ist verschenkte Leistung! Arbeitsspeicher ist eben nicht dann gut genutzt wenn er möglichst frei ist sondern wenn er dynamisch möglichst voll ist! Hier bitte ganz bewusst unterscheiden zwischen voll und zu klein. Das ist was völlig unterschiedliches!
Das alles weiß eigentlich jeder bessere Programmierer da draußen seit Jahrzehnten natürlich auch die von Microsoft. Also hat man nach und nach Ende der 90er Jahre damit begonnen, die immer größer werdenden RAM-Mengen in PCs auch dynamisch sinnvoll zu nutzen. Beispiel: Wurde eine Datei von Windows98 von einem Datenträge A auf einen Datenträger B kopiert hat Windows das nicht mehr A --> B gemacht (wo die Datenträger sich gegenseitig ausbremsen) sondern den Ram als Puffer genutzt wenn möglich, sprich A --> RAM --> B. Zusätzlich hat Windows nach abgeschlossenem Kopiervorgang die Datei im Ram einfach drin gelassen wenn man den Ram nicht sonstwie gebraucht hat für den Fall, dass der User die Datei vielleicht noch auf den Datenträger C kopieren will war das dann bedeutend schneller da sofort aus dem RAM gelesen werden konnte. Eine sehr sinnvolle Nutzung von sonst nicht benötigtem RAM, oder? Blöderweise zeigte die Auslastungsanzeige des RAMs dadurch aber schnell Werte nahe der 100%, denn Windows begann, den vorhandenen RAM tatsächlich sinnvoll zu nutzen und Daten die vielleicht nochmal gebraucht wurden einfach liegen zu lassen. Das war kein Problem, denn sobald ein anderes Programm mehr RAM anforderte wurden die alten Daten rausgeworfen und alles war wieder gut. Und jetzt darf geraten werden, wie die breite Masse darauf reagiert hat, dass ein neues Betriebssystem immer anzeigt der RAM ist voll. Und nach einer sauteuren Aufrüstung von 32 auf 64 MiB RAM war er danach ja schon wieder voll! Der Shitstorm war wegen des damaligen Standes des Internets zwar überschaubar, dennoch war das Geschrei aber groß genug dass Microsoft reagieren musste. Noch heute gibt es unzählige User die mit irgendwelchen Schwachsinnstools ihren RAM freischaufeln wollen und das schöne Caching von Windows damit zerschießen. Die Tools machen dabei nichts als Windows zu sagen gib mir allen RAM den du hast. Windows löscht alle nicht zwingend benötigten Daten im RAM, weist den ganzen RAM dem Tool zu und das Tool sagt dann ok, beende die Zuweisung und der RAM ist leer (und alles was gecacht war muss erneut nachgeladen werden Glückwunsch).
Natürlich wurde bis heute an der sinnvollen RAM-Nutzung nichts geändert. Auch Windows XP, 7, 8, 10 macht dasselbe wie Win98 damals und lässt alte Daten im RAM liegen bis man den Speicher sonstwie braucht. Nur: Man zeigt es dem Nutzer einfach nicht mehr an denn was er nicht weiß macht ihn nicht heiß. Etwas versteckt gibt es die Zahlen noch im Task-Manager zu sehen. Windows 7 unterschied noch von Insgesamt, Verfügbar, Im Cache und frei wobei nur das frei tatsächlich leer bedeutet und hier steht in aller Regel wenn der PC schon etwas länger an ist eine Null. Windows10 nennts noch etwas kryptischer available, committed, cached usw. aber alle haben sie gemeinsam: Der RAM wird komplett vollgeklatscht und genutzt bis zum letzten MB. Die schönen bunten Graphen zeigen das natürlich nicht an, hier wird der ich nenne es mal Datencache einfach weggelassen damit sich der Pöbel nicht darüber aufregt dass beispielsweise Win10 64GiB RAM belegt wenn es sie hat und man viele Daten verschiebt/kopiert.
Diese sinnvolle Speichernutzung hat auch das eine oder andere Entwicklerstudio bereits vor einigen Jahren bei Spielen versucht einzusetzen und es wieder verworfen. Ein Beispiel dafür war das Spiel Lords of the Fallen. Problemlos auf Grafikkarten mit 1,5 GiB vRAM spielbar, belegte das Spiel auch auf einer 12 GB-(damals AMD FirePro-Server-)Grafikkarte den vollen Grafikspeicher. Der Hintergrund: Das Spiel lud an Stellen wo rechentechnisch Zeit dafür war einfach die nachfolgenden Level des Spiels schon mal in den vRAM bis dieser voll war. Resultat war, dass auf Grafikkarten mit viel Speicher die Ladezeiten von einem Level zum nächsten bedeutend kürzer ausfielen. Super Sache, oder? Nein, leider nicht. Da die breite Masse diesen Hintergrund nicht versteht und mittlerweile das Internet eine Märchenverbreitungsmaschine sondergleichen geworden ist haben folgende Spiele das Feature nicht mehr. Der Imageschaden durch Tausende an rumschreienden das schei*-Spiel braucht drölfzig GB vRAM!!!!11eins und darauf folgende sinkende Verkaufszahlen weil andere es auch noch glauben ist deutlich größer als der Vorteil, neue Level schneller laden zu können. Der Michel zu Hause starrt halt lieber länger auf den Ladebalken, so lange er wenigstens sicher ist, dass die Hälfte seines vRAMs auch schön (unsinnig) leer bleibt.
So, Standardkundschaft meines Blogs kennts ja schon, Glückwunsch zum Durchhalten bis zum Ende des nunmehr 40. Blogs (auweia ), Fragen, Anregungen, Kommentare gerne darunter oder per PN.