如何保证RDTSC是准确的?

Joh*_*ica 4 x86 x86-64 rdtsc cpuid

我读过 RDTSC 可以给出错误的读数,不应依赖。
这是真的吗?如果是这样,可以做些什么?

Joh*_*ica 7

非常旧的 CPU 有一个准确的 RDTSC。

问题

然而,较新的 CPU 有问题。
工程师们认为 RDTSC 非常适合告诉时间。
但是,如果 CPU 限制频率,则 RDTSC 对告诉时间毫无用处。
前面提到的脑残工程师决定通过让 TSC 始终以相同的频率运行来“解决”这个问题,即使 CPU 速度变慢。

这具有“优势”,即 TSC 可用于告知已用(挂钟)时间。然而,它使 TSC对分析没有用处。

如何判断你的CPU没有坏

您可以通过读取TSC_invariantCPUID 中的位来判断您的 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}
Run Code Online (Sandbox Code Playgroud)

如何解决乱序执行问题

请参阅: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;
Run Code Online (Sandbox Code Playgroud)

如何在损坏的 CPU 上运行 RDTSC

诀窍是强制 CPU 以 100% 运行。
这通常通过多次运行示例代码来完成。
我通常使用 1.000.000 开始。
然后我将这 100 万次运行计时 10 倍,并使用这些尝试中最短的时间。

与理论时序的比较表明,这给出了非常准确的结果。