【发布时间】:2016-06-19 14:11:35
【问题描述】:
我了解到 RDTSC 可能会给出错误的读数,因此不应依赖它。
这是真的吗?如果是这样,我们可以做些什么?
【问题讨论】:
我了解到 RDTSC 可能会给出错误的读数,因此不应依赖它。
这是真的吗?如果是这样,我们可以做些什么?
【问题讨论】:
非常旧的 CPU 有一个准确的 RDTSC。
但是较新的 CPU 有问题。
工程师们认为 RDTSC 非常适合显示时间。
但是,如果 CPU 限制频率,RDTSC 就无法告诉时间。
上述脑残工程师随后决定通过让 TSC 始终以相同的频率运行来“解决”这个问题,即使 CPU 变慢也是如此。
这具有 TSC 可用于显示经过(挂钟)时间的“优势”。然而,它使 TSC 无用 对分析的用处不大。
您可以通过读取 CPUID 中的TSC_invariant 位来判断您的 CPU 是否正常。
将EAX设置为80000007H并读取EDX的第8位。
如果它是 0,那么你的 CPU 没问题。
如果它是 1,那么您的 CPU 已损坏,您需要确保在全速运行 CPU 时进行配置。
function IsTimerBroken: boolean;
{$ifdef CPUX86}
asm
//Make sure RDTSC measure CPU cycles, not wall clock time.
push ebx
mov eax,$80000007 //Has TSC Invariant support?
cpuid
pop ebx
xor eax,eax //Assume no
and edx,$10 //test TSC_invariant bit
setnz al //if set, return true, your PC is broken.
end;
{$endif}
//Make sure RDTSC measure CPU cycles, not wall clock time.
{$ifdef CPUX64}
asm
mov r8,rbx
mov eax,$80000007 //TSC Invariant support?
cpuid
mov rbx,r8
xor eax,eax
and edx,$10 //test bit 8
setnz al
end;
{$endif}
使用以下代码:
function RDTSC: int64;
{$IFDEF CPUX64}
asm
{$IFDEF AllowOutOfOrder}
rdtsc
{$ELSE}
rdtscp // On x64 we can use the serializing version of RDTSC
push rbx // Serialize the code after, to avoid OoO sneaking in
push rax // later instructions before the RDTSCP runs.
push rdx // See: http://www.intel.de/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf
xor eax,eax
cpuid
pop rdx
pop rax
pop rbx
{$ENDIF}
shl rdx,32
or rax,rdx
{$ELSE}
{$IFDEF CPUX86}
asm
{$IFNDEF AllowOutOfOrder}
xor eax,eax
push ebx
cpuid // On x86 we can't assume the existance of RDTSP
pop ebx // so use CPUID to serialize
{$ENDIF}
rdtsc
{$ELSE}
error!
{$ENDIF}
{$ENDIF}
end;
诀窍是强制 CPU 以 100% 运行。
这通常通过多次运行示例代码来完成。
我通常使用 1.000.000 开头。
然后,我将这 100 万次运行计时 10 倍,并采用这些尝试中最短的时间。
与理论时间的比较表明,这给出了非常准确的结果。
【讨论】:
hlt 睡眠状态期间不会停止,这也使它无法用作时间源。 Linux /proc/cpuinfo 将此称为nonstop_tsc。由于乱序执行,使用rdtsc 对极短的指令序列进行计时也是有问题的。 rdtscp 可以为此提供帮助,但其他用途可能需要完整的序列化指令,以确保 rdtsc 指令不会通过其他 insn,并且其他 insn 不会通过它。对于分析,请使用性能计数器。
rdtsc 为什么它被破坏对我来说是个谜。添加一个与主时钟同步/不同步的额外计时器会杀死英特尔吗?
lfence序列化它和定时区域之间的管道)。