GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum beginnt diese Verzögerungsschleife nach mehreren Iterationen ohne Schlaf schneller zu laufen?

Nach 26 Iterationen fährt Linux die CPU auf die maximale Taktrate hoch, da Ihr Prozess ein paar Mal hintereinander seine volle Zeitscheibe verwendet.

Wenn Sie mit Leistungszählern anstelle der Uhrzeit nachsehen, würden Sie sehen, dass die Kerntaktzyklen pro Verzögerungsschleife konstant blieben, was bestätigt, dass dies nur ein Effekt von DVFS ist (das alle modernen CPUs verwenden, um mit mehr Energie zu laufen). effiziente Frequenz und Spannung die meiste Zeit).

Wenn Sie auf einem Skylake mit Kernel-Unterstützung für den neuen Energieverwaltungsmodus (bei dem die Hardware die volle Kontrolle über die Taktrate übernimmt) getestet haben, würde das Hochfahren viel schneller erfolgen.

Wenn Sie es für eine Weile auf einer Intel-CPU mit Turbo laufen lassen, werden Sie wahrscheinlich feststellen, dass die Zeit pro Iteration wieder leicht ansteigt, sobald die thermischen Grenzen erfordern, dass die Taktfrequenz wieder auf die maximal anhaltende Frequenz reduziert wird. (Siehe Warum kann meine CPU die Spitzenleistung in HPC nicht aufrechterhalten, um mehr darüber zu erfahren, wie Turbo die CPU schneller laufen lässt, als sie für Hochleistungs-Workloads aufrechterhalten kann.)

Einführung von 01 verhindert, dass der CPU-Frequenzregler von Linux die Taktrate erhöht, da der Prozess selbst bei minimaler Frequenz keine 100%ige Last erzeugt. (Das heißt, die Heuristik des Kernels entscheidet, dass die CPU schnell genug für die darauf ausgeführte Arbeitslast läuft.)

Kommentare zu anderen Theorien :

Betreff:Davids Theorie, dass ein möglicher Kontextwechsel von 10 könnte Caches verschmutzen:Das ist im Allgemeinen keine schlechte Idee, aber es hilft nicht, diesen Code zu erklären.

Cache-/TLB-Verschmutzung ist für dieses Experiment überhaupt nicht wichtig . Es gibt im Grunde nichts innerhalb des Zeitfensters, das den Speicher außer dem Ende des Stapels berührt. Die meiste Zeit wird in einer winzigen Schleife (1 Zeile Anweisungs-Cache) verbracht, die nur einen 28 berührt des Stapelspeichers. Jede potenzielle Cache-Verschmutzung während 32 ist ein winziger Bruchteil der Zeit für diesen Code (echter Code wird anders sein)!

Ausführlicher für x86:

Der Aufruf von 40 selbst kann einen Cache-Miss verursachen, aber ein Code-Fetch-Cache-Miss verzögert die Messung der Startzeit, anstatt Teil dessen zu sein, was gemessen wird. Der zweite Aufruf von 58 wird fast nie verzögert, da es immer noch heiß im Cache sein sollte.

Die 61 Die Funktion befindet sich möglicherweise in einer anderen Cache-Zeile als 73 (da gcc 80 markiert als "kalt", also wird es weniger optimiert und mit anderen kalten Funktionen/Daten platziert). Wir können mit ein oder zwei Befehls-Cache-Fehlschlägen rechnen. Sie befinden sich jedoch wahrscheinlich immer noch auf derselben 4k-Seite, also 90 wird den potenziellen TLB-Fehlschlag ausgelöst haben, bevor er in den zeitgesteuerten Bereich des Programms eingetreten ist.

gcc -O0 kompiliert den OP-Code in etwa so (Godbolt Compiler Explorer):Behält den Schleifenzähler im Speicher auf dem Stack.

Die leere Schleife hält den Schleifenzähler im Stapelspeicher, sodass die Schleife auf einer typischen Intel x86-CPU mit einer Iteration pro ~6 Zyklen auf der IvyBridge-CPU des OP ausgeführt wird, dank der Speicherweiterleitungslatenz, die Teil von 107 mit einem Speicherziel (Lesen-Ändern-Schreiben). 115 beträgt 600.000 Zyklen, was den Beitrag von höchstens ein paar Cache-Fehlschlägen dominiert (jeweils ~200 Zyklen für Code-Fetch-Fehlschläge, die verhindern, dass weitere Anweisungen ausgegeben werden, bis sie aufgelöst sind).

Out-of-Order-Ausführung und Store-Forwarding sollten den potenziellen Cache-Miss beim Zugriff auf den Stack größtenteils verbergen (als Teil der 120 Anleitung).

Selbst wenn der Loop-Counter in einem Register gehalten wird, sind 100.000 Zyklen viel.


Ein Anruf bei 134 kann zu einem Kontextwechsel führen oder auch nicht. Wenn dies der Fall ist, dauert es länger, als wenn dies nicht der Fall ist.


Linux
  1. Warum funktioniert Tomcat mit Port 8080, aber nicht mit 80?

  2. Warum einen Linux-Shell-Befehl mit '&' ausführen?

  3. Wie kann ich einen Befehl verzögert im Hintergrund ausführen?

  4. Warum schlägt das Einbinden einer Datei nach dem Aufheben der Verknüpfung mit ENOENT fehl?

  5. Sollte ich versuchen, meine Threads auszugleichen, oder tut Linux dies?

Linux – Wie funktioniert Load Average mit modernen CPUs?

Warum speichert Bash keine Befehle, die mit Leerzeichen beginnen?

Warum zeigt das Htop-Meter> 90 % an, während die Tabelle 0,0 % anzeigt?

Warum sagt rm manual, dass wir es ohne Argumente ausführen können, wenn das nicht stimmt?

PHP-FPM startet nach dem Neustart nicht automatisch

Warum wird dieser ldapadd-Befehl mit einem ungültigen Syntaxfehler beendet?