我读过RDTSC可以提供错误的读数,不应该依赖它 这是真的,如果可以的话可以做些什么呢?
答案 0 :(得分:4)
很老的CPU有一个准确的RDTSC。
问题
然而,较新的CPU有问题
工程师们认为,RDTSC非常适合讲述时间
但是,如果CPU限制频率,RDTSC对于告诉时间毫无用处
上述脑死亡工程师然后决定“修复”。这个问题是让TSC始终以相同的频率运行,即使CPU减速也是如此。
这具有“优势”' TSC可用于告知经过的(挂钟)时间。然而,这使得TSC 无用对分析不太有用。
如何判断您的CPU是否坏了
您可以通过读取CPUID中的TSC_invariant
位来判断CPU是否正常。
将AEX
设置为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}
如何修复乱序执行问题
请参阅:http://www.intel.de/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf
使用以下代码:
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倍,并采取这些尝试的最低时间。
与理论时间的比较表明,这给出了非常准确的结果。