如何保证RDTSC是准确的? [英] How to ensure that RDTSC is accurate?

查看:48
本文介绍了如何保证RDTSC是准确的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经读到 RDTSC 可以提供错误的读数,不应依赖.
这是真的吗?如果是这样,我们可以做些什么?

I've read that RDTSC can gives false readings and should not be relied upon.
Is this true and if so what can be done about it?

推荐答案

非常老的 CPU 有一个准确的 RDTSC.

Very old CPU's have a RDTSC that is accurate.

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

However newer CPU's have a problem.
Engineers decided that RDTSC would be great for telling time.
However if a CPU throttles the frequency RDTSC is useless for telling time.
The aforementioned braindead engineers then decided to 'fix' this problem by having the TSC always run at the same frequency, even if the CPU slows down.

这具有优势",即 TSC 可用于告知已用(挂钟)时间.然而,它使得 TSC 无用 对分析的用处不大.

This has the 'advantage' that TSC can be used for telling elapsed (wall clock) time. However it makes the TSC useless less useful for profiling.

您可以通过读取 CPUID 中的 TSC_invariant 位来判断您的 CPU 是否正常.

You can tell if your CPU is fine by reading the TSC_invariant bit in the CPUID.

设置EAX为80000007H,读取EDX的第8位.
如果它是 0,那么你的 CPU 没问题.
如果它是 1,那么您的 CPU 已损坏,您需要确保在 CPU 全速运行时进行配置.

Set EAX to 80000007H and read bit 8 of EDX.
If it is 0 then your CPU is fine.
If it's 1 then your CPU is broken and you need to make sure you profile whilst running the CPU at full throttle.

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 倍并在这些尝试中使用最短的时间.

How to run RDTSC on a broken CPU

The trick is to force the CPU to run at 100%.
This is usually done by running the sample code many many times.
I usually use 1.000.000 to start with.
I then time those 1 million runs 10x and take the lowest time of those attempts.

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

Comparisons with theoretical timings show that this gives very accurate results.

这篇关于如何保证RDTSC是准确的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆