1

我正在使用 rdtsc 和 cpuid 指令(使用易失性内联汇编指令)来测量程序的 CPU 周期。rdtsc 指令为我在 Linux(使用速度优化 -o2 -fomit-frame-pointer)和 Windows(使用 MS Visual Studio 2008 的速度优化选项 C 编译器(我认为它的 VC 9.0))上的程序提供了真实的结果。

最近,我实现了一个新程序,它使用了大量的表格查找和类似的东西。然而,这个程序在 Linux 上使用 gcc 优化的 rdtsc 测量结果总是比我预期的错误测量结果(非常少的 CPU 周期数)。同一程序在 Windows 上运行时的 rdtsc 测量结果(使用我上面提到的优化和编译器编译)是现实的,并且符合预期。

我的问题是 gcc 优化有什么方法可以将易失性汇编指令移动到产生上述行为的地方?

我的计时器代码如下:

#define TIMER_VARS                                                 \
  uint32 start_lo, start_hi;                                       \
  uint32 ticks_lo, ticks_hi

#define TIMER_START()                                              \
  __asm__ __volatile__                                             \
     ("rdtsc"                                                      \
     : "=a" (start_lo), "=d" (start_hi) /* a = eax, d = edx*/      \
     : /* no input parameters*/                                    \
     : "%ebx", "%ecx", "memory")

#define TIMER_STOP()                                               \
  __asm__ __volatile__                                             \
     ("rdtsc"                                                      \
     "\n        subl %2, %%eax"                                    \
     "\n        sbbl %3, %%edx"                                    \
     : "=&a" (ticks_lo), "=&d" (ticks_hi)                          \
     : "g" (start_lo), "g" (start_hi)                              \
     : "%ebx", "%ecx", "memory")

如果有人能就此提出一些想法,我将不胜感激。

谢谢,

4

2 回答 2

3

为了防止内联rdtsc函数在任何加载/存储/其他操作中移动,您应该将 asm 编写为__asm__ __volatile__并包含"memory"在 clobber 列表中。如果不执行后者,则 GCC 无法删除 asm 或将其移动到可能需要 asm 的结果(或更改输入)的任何指令中,但它仍然可以针对不相关的操作移动它。"memory"clobber 意味着 GCC 不能对内存内容(地址可能被泄露的任何变量)在整个 asm 中保持不变做出任何假设,因此移动它变得更加困难。但是,GCC仍然可以在只修改地址从未被占用的局部变量的指令之间移动 asm(因为它们不是"memory")。

哦,正如 wildplasser 在评论中所说,在你浪费大量时间之前检查 asm 输出。

于 2012-05-09T16:02:21.580 回答
1

我不知道它是否正确,但我曾经使用的代码是:

#define rdtscll(val) \
      __asm__ __volatile__("rdtsc" : "=A" (val))

typedef unsigned unsigned long long Ull;

static inline Ull myget_cycles (void)
{
Ull ret;

rdtscll(ret);
return ret; 
}

我记得它在英特尔上比在 AMD 上“慢”。YMMV。

于 2012-05-10T17:09:39.723 回答