rdtsc计时器在linux中是不准确的吗?

时间:2013-10-16 09:11:43

标签: c++ linux

 __inline__ uint64_t rdtsc() {
    uint32_t low, high;
    __asm__ __volatile__ (
        "xorl %%eax,%%eax \n    cpuid"
        ::: "%rax", "%rbx", "%rcx", "%rdx" );
    __asm__ __volatile__ (
                          "rdtsc" : "=a" (low), "=d" (high));
    return (uint64_t)high << 32 | low;
}

我在程序中使用了上面的rdtsc函数作为计时器: 以下代码产生312-344个时钟周期:

 start = rdtsc();
 stop = rdtsc();

 elapsed_ticks = (unsigned)((stop-start));
 printf("\n%u ticks\n",elapsed_ticks);

每次运行上面的代码我都会得到不同的值。这是为什么?

我在Visual C ++中运行了相同的代码,它在“intrin.h”中使用了rdtsc函数。我得到了18个时钟的恒定值。是的,每次运行都是恒定的!有人可以解释一下吗?谢谢!

2 个答案:

答案 0 :(得分:6)

使用TSC获取可靠的时间戳非常困难。主要问题是:

  • 在旧的多核处理器上,不同核心的速率可能会有不同的变化,因为它们会根据不同的负载调整时钟速度;
  • 在更新的处理器上,速率在时钟速度变化时保持不变,因此轻载核心的时序可能看起来比它们慢。
  • 乱序执行可能意味着您认为寄存器不会被读取。

您的函数正在执行cpuid指令并忽略其结果,以及读取TSC,以尝试缓解上一个问题。这是一个序列化指令,强制按顺序执行。但是,它也是一个缓慢的指令,如果你试着测量极短的时间,会影响结果。

如果我从函数中删除该指令,使其等效于您在VC ++中使用的内在函数:

inline uint64_t rdtsc() {
    uint32_t low, high;
    asm volatile ("rdtsc" : "=a" (low), "=d" (high));
    return (uint64_t)high << 32 | low;
}

然后我得到更一致的值,但重新引入潜在的指令排序问题。

另外,请确保您正在使用优化进行编译(例如-O3如果您正在使用GCC),否则该函数可能不会内联。

答案 1 :(得分:0)

因为您的进程不是系统上运行的唯一进程。它可能会在任何时候被抢占,导致你的过程进入睡眠状态一段时间。