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%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.
Es gibt viele Gründe, eine große Zahl zu bekommen:
Beachten Sie, dass rdtsc
für das Timing ohne Arbeit nicht besonders zuverlässig ist, weil:
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?
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:
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.
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%