我读过 RDTSC 可以给出错误的读数,不应该依赖。
这是真的吗?如果是这样,可以做些什么呢?
问问题
1466 次
1 回答
7
非常旧的 CPU 有一个准确的 RDTSC。
问题
但是较新的 CPU 有问题。
工程师们认为 RDTSC 非常适合显示时间。
但是,如果 CPU 限制频率,RDTSC 就无法告诉时间。
前面提到的脑残工程师随后决定通过让 TSC 始终以相同的频率运行来“解决”这个问题,即使 CPU 速度变慢也是如此。
这具有 TSC 可用于告知经过(挂钟)时间的“优势”。然而,它使 TSC对分析没有用处。
如何判断你的 CPU 没有坏
TSC_invariant
您可以通过读取CPUID 中的位来判断您的 CPU 是否正常。
设置EAX
为 80000007H 并读取EDX
.
如果它是 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 上运行 RDTSC
诀窍是强制 CPU 以 100% 运行。
这通常通过多次运行示例代码来完成。
我通常使用 1.000.000 开始。
然后,我将这 100 万次运行计时 10 倍,并采用这些尝试中最短的时间。
与理论时间的比较表明,这给出了非常准确的结果。
于 2016-03-05T20:57:04.670 回答