如何保证RDTSC是准确的?

How to ensure that RDTSC is accurate?

我了解到 RDTSC 可能会给出错误的读数,因此不应依赖。
这是真的吗?如果是,可以做些什么?

非常老 CPU 的 RDTSC 是准确的。

问题

但是较新的 CPU 有问题。
工程师们认为 RDTSC 非常适合报时。
但是,如果 CPU 限制频率,RDTSC 就无法告诉时间。
前面提到的脑残工程师然后决定 'fix' 这个问题,让 TSC 始终 运行 在相同的频率,即使 CPU 变慢。

这有 'advantage' TSC 可以用来告诉流逝的(挂钟)时间。但是,它使 TSC 无用 对分析的用处不大。

如何判断你的CPU是否坏了

您可以通过读取 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,000007  //Has TSC Invariant support?
  cpuid
  pop ebx
  xor eax,eax        //Assume no
  and edx,        //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,000007  //TSC Invariant support?
  cpuid
  mov rbx,r8
  xor eax,eax
  and edx, //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;

如何 运行 RDTSC 损坏 CPU

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

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