rdtsc, zu viele Zyklen
#include <stdio.h>
static inline unsigned long long tick()
{
unsigned long long d;
__asm__ __volatile__ ("rdtsc" : "=A" (d) );
return d;
}
int main()
{
long long res;
res=tick();
res=tick()-res;
printf("%d",res);
return 0;
}
Habe ich kompiliert den code mit gcc -O0 -O1 -O2 -O3 Optimierungen. Und ich bekomme immer 2000-2500 Zyklen. Kann mir jemand erklären, warum diese Ausgabe? Wie verbringen Sie diese Zyklen?
Erste Funktion "tick" ist falsch. Dieses Recht ist.
Andere version der Funktion "tick"
static __inline__ unsigned long long tick()
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}
Dies ist Assembler-code, der für -O3
.file "rdtsc.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%d"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movl %ecx, -16(%ebp)
movl %ebx, -12(%ebp)
movl %esi, -8(%ebp)
movl %edi, -4(%ebp)
#APP
# 6 "rdtsc.c" 1
rdtsc
# 0 "" 2
#NO_APP
movl %edx, %edi
movl %eax, %esi
#APP
# 6 "rdtsc.c" 1
rdtsc
# 0 "" 2
#NO_APP
movl %eax, %ecx
movl %edx, %ebx
subl %esi, %ecx
sbbl %edi, %ebx
movl %ecx, 4(%esp)
movl %ebx, 8(%esp)
movl $.LC0, (%esp)
call printf
movl -16(%ebp), %ecx
xorl %eax, %eax
movl -12(%ebp), %ebx
movl -8(%ebp), %esi
movl -4(%ebp), %edi
movl %ebp, %esp
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (Debian 4.3.2-1.1) 4.3.2"
.section .note.GNU-stack,"",@progbits
Dies ist CPU -
processor : 0
vendor_id : GenuineIntel
cpu family : 15
model : 4
model name : Intel(R) Xeon(TM) CPU 3.00GHz
stepping : 3
cpu MHz : 3000.105
cache size : 2048 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 5
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss constant_tsc up pebs bts pni
bogomips : 6036.62
clflush size : 64
- Viel bedeutet Sie nicht zählen es. Verwenden viele statt.
- oh, danke )
rdtsc
schreibt in %edx:%eax`. Ihr tick() Funktion ist falsch.- mit der zweiten Funktion die gleiche Ausgabe
- natürlich, mit =Einer wird zurückkehren unteren 32 bits auf x86_64 nur, und die unteren 32 bits sind genug für diesen test
- Stellen Sie sicher, dass Sie verstehen, warum
rdtsc
ist nicht eine zuverlässige timer. - Sicher können Sie helfen, die OP auf, warum Sie dies sagen.
- Bei mir läuft dein code, ich habe fast immer das bekommen, 42. Douglas Adams würde glücklich sein. 🙂
- Welches Betriebssystem verwenden Sie für diesen test (die Distribution und kernel-version)?
- Linux-version 2.6.26-2-686 (Debian 2.6.26-26lenny1) ([email protected]) (gcc version 4.1.3 20080704 (prerelease) (Debian 4.1.2-25)) #1 SMP Thu Nov 25 01:53:57 UTC 2010
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich habe versucht deinen code auf mehrere Linux-Distributionen laufen auf verschiedenen Intel-CPUs (zugegeben, alle neuer als der Pentium 4 HT 630 Sie zu sein scheinen, verwenden). In all den tests, die ich bekam Werte zwischen 25 und 50 Zyklen.
Meine einzige Hypothese, die konsistent mit allen beweisen ist, dass Sie Ihr Betriebssystem in einer virtuellen Maschine, statt auf blankem Metall, und die TSC ist immer virtualisiert.
Es gibt viele Gründe, um eine große Anzahl:
Beachten Sie, dass
rdtsc
ist nicht besonders zuverlässig für timing, ohne Arbeit, denn:Meisten Betriebsystemen Systeme haben einen hochpräzisen Takt oder timing-Methode.
clock_gettime
auf Linux zum Beispiel, vor allem die monotonen Uhren. (Verstehen Sie auch den Unterschied zwischen eine Wand-Uhr und eine monotone Uhr: eine Wanduhr kann rückwärts zu bewegen — auch in UTC.) Auf Windows, ich denke, die Empfehlung istQueryHighPerformanceCounter
. In der Regel sind diese Uhren bieten mehr als genug Genauigkeit für die meisten Bedürfnisse.Sich auch, einen Blick auf die Versammlung, wie es aussieht, sind nur 32-bit der Antwort: ich sehe nicht
%edx
gerettet, nachdemrdtsc
.Ihren code ausführen, bekomme ich die timings von 120-150 ns für
clock_gettime
mitCLOCK_MONOTONIC
, und 70-90 Zyklen für rdtsc (~20 ns bei voller Geschwindigkeit, aber ich vermute, der Prozessor ist getaktet nach unten, und das ist wirklich über 50 ns). (Auf einlaptopdesktop (verdammt, SSH, vergaß die Maschine, die ich war!) das ist bei etwa konstant 20% CPU-Nutzung) Sicher, dass Ihre Maschine nicht verzetteln?struct timespec ts1,ts2; clock_gettime(CLOCK_MONOTONIC,&ts1); clock_gettime(CLOCK_MONOTONIC,&ts2);
ts2.tv_nsec-ts1.tv_nsec ~8000 ist er zu groß.=A
kopiert Werte von edx und eax.%edx
gerettet in der Montage?=A
Einschränkung kopieren die beiden Register eax und edx zur angegebenen Position.%edx
.Es sieht aus wie dein OS deaktiviert die Ausführung von RDTSC im user-space. Und Ihre Anwendung schalten auf kernel-und zurück, das eine Menge von Zyklen.
Dies ist von der Intel Software Developer ' s Manual:
Edit:
Beantwortung aix Kommentar, ich erklären, warum TSD ist wahrscheinlich der Grund dafür ist hier.
Ich kenne nur diese Möglichkeiten für ein Programm zum ausführen einer einzelnen Anweisung mehr als üblich:
Ersten 2 Gründe können in der Regel keine verzögerte Ausführung für mehr als ein paar hundert Zyklen. 2000-2500 Zyklen sind typisch für Kontext/kernel wechseln. Aber es ist praktisch unmöglich, zu fangen ein context-switch mehrere Male auf der gleichen Stelle. So sollte es sein, kernel wechseln. Was bedeutet, dass entweder das Programm läuft unter einem debugger oder RDTSC ist nicht erlaubt in den user-Modus.
Ist der wahrscheinlichste Grund für OS deaktivieren RDTSC kann Sicherheit sein. Es gab versuche, die RDTSC knacken von Verschlüsselungs-Programmen.
clock_gettime
ähnliche Erklärungen? Ich habe 8000 nsec mitCLOCK_MONOTONIC
id. Es ist riesig=/Instruction cache miss? (dies ist meine Vermutung)
Auch, möglicherweise,
Schalter hypervisor in einem virtualisierten system?
Reste der bootstrap-Programm (einschließlich Netzwerk-Aktivität auf der gleichen CPU)?
Zu Thanatos: Auf Systemen neuer als 2008, rdtsc() ist eine Wanduhr und variiert nicht mit der Frequenz Schritte.
Können Sie versuchen, diese wenig code?
Nur eine Idee - vielleicht sind diese zwei rdtsc-Instruktionen werden ausgeführt auf verschiedenen Kernen? rdtsc Werte können leicht variieren über Kerne.