18 Stimmen

"cpuid" vor "rdtsc"

Manchmal stoße ich auf Code, der die TSC mit rdtsc Anweisung, sondern ruft cpuid direkt davor.

Warum ist ein Anruf cpuid notwendig? Mir ist klar, dass es etwas damit zu tun haben könnte, dass verschiedene Kerne TSC-Werte haben, aber was genau was passiert, wenn Sie diese beiden Anweisungen nacheinander aufrufen?

19voto

paxdiablo Punkte 809679

Es soll verhindern, dass die Ausführung außer der Reihe erfolgt. Dieser Text stammt aus einem Artikel mit dem Titel "Performance monitoring" von John Eckerdal, der inzwischen aus dem Internet verschwunden ist (aber zufällig hierher kopiert wurde, bevor er verschwand):

Die Pentium Pro- und Pentium II-Prozessoren unterstützen die Out-of-Order-Ausführung von Befehlen, die in einer anderen Reihenfolge ausgeführt werden, als Sie sie programmiert haben. Dies kann eine Fehlerquelle sein, wenn nicht darauf geachtet wird.

Um dies zu verhindern, muss der Programmierer die Befehlswarteschlange serialisieren. Dies kann durch Einfügen einer serialisierenden Anweisung wie der CPUID-Anweisung vor der RDTSC-Anweisung erfolgen.

6voto

Tony Delroy Punkte 98528

Aus zwei Gründen:

  • Wie paxdiablo sagt, stellt die CPU, wenn sie einen CPUID-Opcode sieht, sicher, dass alle vorhergehenden Anweisungen ausgeführt werden und dann die CPUID genommen wird, bevor die nachfolgenden Anweisungen ausgeführt werden. Ohne eine solche Anweisung kann die CPU-Ausführungspipeline am Ende TSC vor der/den Anweisung(en) ausführen, die Sie zeitlich festlegen möchten.
  • Bei einem erheblichen Anteil der Rechner gelingt es nicht, die TSC-Register zwischen den Kernen zu synchronisieren. Wenn Sie es auslesen wollen a aus dem Mund eines Pferdes. http://msdn.microsoft.com/en-us/library/ee417693%28VS.85%29.aspx . Wenn Sie also ein Intervall zwischen den TSC-Messungen messen, haben Sie ein zufälliges, aber möglicherweise konstantes (siehe unten) Intervall eingeführt - es kann leicht mehrere Sekunden (ja, Sekunden) betragen, sogar kurz nach dem Hochfahren. Dies spiegelt effektiv wider, wie lange das BIOS auf einem einzelnen Kern gelaufen ist, bevor es die anderen abgeschaltet hat, plus - wenn Sie irgendwelche unangenehmen Energiesparoptionen aktiviert haben - eine zunehmende Drift, die durch Kerne verursacht wird, die mit unterschiedlichen Frequenzen laufen oder sich wieder abschalten. Wenn Sie also die Threads, die TSC-Register lesen, nicht an denselben Kern gebunden haben, müssen Sie eine Art kernübergreifende Delta-Tabelle erstellen und die Kern-ID (die von CPUID zurückgegeben wird) jeder TSC-Probe kennen, um diesen Versatz auszugleichen. Das ist ein weiterer Grund, warum Sie CPUID neben RDTSC sehen können, und in der Tat ein Grund, warum viele Betriebssysteme mit neueren RDTSCP die Kern-ID-Nummern in den zusätzlichen TSC_AUX[31:0]-Daten speichern. (Ab Core i7 und Athlon 64 X2 ist RDTSCP in jeder Hinsicht eine viel bessere Option - das Betriebssystem gibt Ihnen normalerweise die Core-ID wie erwähnt, atomar zum TSC-Lesen, y Umordnung von Anweisungen verhindern).

3voto

Peter Cordes Punkte 279904

CPUID wird serialisiert, wodurch die Ausführung von RDTSC außerhalb der Reihenfolge verhindert wird.

Heutzutage können Sie stattdessen sicher LFENCE verwenden. Es ist dokumentiert als Serialisierung auf dem Befehlsstrom (aber nicht speichert in den Speicher) auf Intel-CPUs, und jetzt auch auf AMD nach ihrer Microcode-Update für Spectre.

https://hadibrais.wordpress.com/2018/05/14/the-significance-of-the-x86-lfence-instruction/ erklärt mehr über LFENCE.

Siehe auch https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf für eine Möglichkeit, RDTSC zu verwenden P die CPUID (oder LFENCE) aus dem zeitlich begrenzten Bereich heraushält:

LFENCE     ; (or CPUID) Don't start the timed region until everything above has executed
RDTSC           ; EDX:EAX = timestamp
mov  ebx, eax   ; low 32 bits of start time

   code under test

RDTSCP     ; built-in one way barrier stops it from running early
LFENCE     ; (or CPUID) still use a barrier after to prevent anything weird
sub  eax, ebx   ; low 32 bits of end-start

Siehe auch CPU-Zykluszahl abrufen? für weitere Informationen über RDTSC-Caveats, wie constant_tsc und nonstop_tsc.

Als Bonus erhalten Sie mit RDTSCP eine Kern-ID. Sie könnten RDTSCP auch für die Startzeit verwenden, wenn Sie die Kernmigration überprüfen wollen. Aber wenn Ihre CPU die constant_tsc Features sollten alle Kerne im Paket ihre TSCs synchronisiert haben, so dass Sie dies auf modernen x86-Systemen normalerweise nicht benötigen.

Sie können die Kern-ID stattdessen von CPUID abrufen, wie in der Antwort von @Tony dargelegt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X