【问题标题】:Is rdtsc timer inaccurate in linux?rdtsc 计时器在 linux 中是否不准确?
【发布时间】:2013-10-16 09:11:43
【问题描述】:
 __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 个时钟的恒定值。是的,每次运行都是恒定的!有人可以解释一下吗?谢谢!

【问题讨论】:

  • 你不需要内联汇编。 Get CPU cycle count? 有内在函数,以及一些关于警告的细节。

标签: c++ linux


【解决方案1】:

使用 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),否则该函数可能不会被内联。

【讨论】:

  • 感谢回复,我应该在编译时应用哪些优化?
  • @sanjay_c0d3r:假设您使用的是 GCC,那么-O3 将启用(​​或多或少)所有有用的优化。但是我刚刚进行了更多研究以找出该指令存在的原因,听起来如果您想从 TSC 寄存器中获得准确的结果,您需要非常小心。请参阅我的更新答案。
【解决方案2】:

因为您的进程不是系统上唯一运行的进程。它可能随时被抢占,导致您的进程进入休眠状态。

【讨论】:

  • 我认为被抢占的进程将花费超过 32 个时钟 (344-312) 的时间。
  • 如何解释“intrin.h”库中的 rdtsc 函数。为什么它总是恒定的?另外,有没有办法在linux中运行一个程序来禁用抢占?
  • @sanjay_c0d3r 你是说你包含 intrin.h,并使用它的 rdtsc 宏/函数,一切都符合预期吗?那么你制作的组件可能有一些问题。
  • @sanjay_c0d3r:即使您认为它有效,也不应该在现代系统上使用 rtdsc。在 Windows 上使用 queryperformancecounter。
猜你喜欢
  • 2016-06-19
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-19
  • 2017-03-29
  • 1970-01-01
相关资源
最近更新 更多