rdtsc, zu viele Zyklen

8
%Vor%

Ich habe diesen Code mit gcc mit -O0 -O1 -O2 -O3-Optimierungen kompiliert. Und ich bekomme immer 2000-2500 Zyklen. Kann jemand den Grund für diese Ausgabe erklären? Wie verbringe ich diese Zyklen?

Erste Funktion "tick" ist falsch. Das ist richtig .

Eine andere Version der Funktion "tick"

%Vor%

Dies ist der Assemblercode für -O3

%Vor%

Dies ist CPU

%Vor%     
eXXXXXXXXXXX2 30.11.2011, 08:01
quelle

5 Antworten

9

Ich habe Ihren Code auf mehreren Linux-Distributionen getestet, die auf verschiedenen Intel-CPUs laufen (zugegebenermaßen alle neuer als der Pentium 4 HT 630, den Sie zu verwenden scheinen). In all diesen Tests habe ich Werte zwischen 25 und 50 Zyklen erhalten.

Meine einzige Hypothese, die mit allen Beweisen übereinstimmt, ist, dass Sie Ihr Betriebssystem in einer virtuellen Maschine anstatt auf Bare-Metal betreiben, und TSC wird virtualisiert.

    
NPE 30.11.2011, 10:50
quelle
6

Es gibt viele Gründe, eine große Zahl zu bekommen:

  • Das Betriebssystem hat einen Kontextwechsel durchgeführt und Ihr Prozess wurde in den Ruhezustand versetzt.
  • Eine Suche nach Datenträgern ist aufgetreten und Ihr Prozess wurde in den Ruhezustand versetzt.
  • ... eine Vielzahl von Gründen, warum Ihr Prozess möglicherweise ignoriert wird.

Beachten Sie, dass rdtsc für das Timing ohne Arbeit nicht besonders zuverlässig ist, weil:

  • Die Prozessorgeschwindigkeiten können sich ändern und somit ändert sich die Länge eines Zyklus (wenn in Sekunden gemessen).
  • Verschiedene Prozessoren können für einen gegebenen Zeitpunkt unterschiedliche Werte für den TSC haben.

Die meisten Betriebssysteme haben eine hochpräzise Takt- oder Timing-Methode. clock_gettime unter Linux zum Beispiel, insbesondere die monotonen Uhren. (Versteht auch den Unterschied zwischen einer Wanduhr und einer monotonen Uhr: Eine Wanduhr kann sich rückwärts bewegen - sogar in UTC.) Unter Windows denke ich, dass die Empfehlung QueryHighPerformanceCounter ist. In der Regel bieten diese Uhren mehr als genug Genauigkeit für die meisten Bedürfnisse.

Wenn Sie sich die Assembly ansehen, sieht es so aus, als ob Sie nur 32-Bit-Antworten erhalten: %edx wird nicht nach rdtsc gespeichert.

Wenn ich deinen Code ausführe, erhalte ich Zeiten von 120-150 ns für clock_gettime mit CLOCK_MONOTONIC und 70-90 Zyklen für rdtsc (~ 20 ns mit voller Geschwindigkeit, aber ich vermute, dass der Prozessor getaktet ist, und das ist wirklich ungefähr 50 ns). (Auf einem Laptop Desktop (verflixter SSH, vergessen, auf welcher Maschine ich war!), Die ungefähr bei einer konstanten CPU-Auslastung von 20% liegt) Sicher, dass Ihre Maschine nicht steckengeblieben ist?

    
Thanatos 30.11.2011 09:31
quelle
4

Offenbar hat Ihr Betriebssystem die Ausführung von RDTSC im Benutzerbereich deaktiviert. Und Ihre Anwendung muss zum Kernel und zurück wechseln, was eine Menge Zyklen erfordert.

Dies stammt aus dem Intel Software Developer's Manual:

  

Wenn im geschützten oder virtuellen 8086-Modus das Flag für Zeitstempel deaktivieren (TSD) aktiviert ist   Das Register CR4 beschränkt die Verwendung des RDTSC-Befehls wie folgt. Wenn das TSD-Flag   Es ist klar, dass der RDTSC-Befehl auf jeder beliebigen Berechtigungsebene ausgeführt werden kann. wenn die Flagge   gesetzt ist, kann die Anweisung nur auf Berechtigungsstufe 0 ausgeführt werden. (Wenn in Real-Adresse   Modus, der RDTSC-Befehl ist immer aktiviert.)

Bearbeiten:

Ich beantworte Aix's Kommentar, ich erkläre, warum TSD wahrscheinlich der Grund dafür ist.

Ich kenne nur diese Möglichkeiten für ein Programm, einen einzelnen Befehl länger als gewöhnlich auszuführen:

  1. Wird unter einem Emulator ausgeführt,
  2. mit selbst modifiziertem Code,
  3. Kontextwechsel,
  4. Kernel-Switch.

Die ersten beiden Gründe können die Ausführung normalerweise nicht für mehr als ein paar hundert Zyklen verzögern. 2000-2500 Zyklen sind typischer für den Kontext / Kernel-Wechsel. Es ist jedoch praktisch unmöglich, einen Kontextwechsel mehrmals am gleichen Ort zu finden. Also sollte es Kernel-Switch sein. Das bedeutet, dass entweder das Programm unter Debugger läuft oder RDTSC im Benutzermodus nicht erlaubt ist.

Der wahrscheinlichste Grund dafür, dass das Betriebssystem RDTSC deaktiviert, ist Sicherheit. Es gab Versuche, RDTSC zu verwenden, um Verschlüsselungsprogramme zu knacken.

    
Evgeny Kluev 30.11.2011 09:46
quelle
1

Instruktions-Cache-Miss? (das ist meine Vermutung)

Auch möglicherweise

Wechseln Sie in einem virtualisierten System zum Hypervisor? Reste des Programm-Bootstrap (einschließlich Netzwerkaktivität auf der gleichen CPU)?

To Thanatos: Auf Systemen, die jünger als 2008 sind, ist rdtsc () eine Wanduhr und variiert nicht mit Frequenzschritten.

Können Sie diesen kleinen Code ausprobieren?

%Vor%     
Perig 31.10.2012 05:05
quelle
0

Nur eine Idee - vielleicht werden diese beiden rdtsc-Anweisungen auf verschiedenen Kernen ausgeführt? Rdtsc-Werte können über Kerne leicht variieren.

    
mifki 30.11.2011 09:36
quelle

Tags und Links