This question already has answers here:
How to get the CPU cycle count in x86_64 from C++?

(4个答案)


2年前关闭。




我已经在gcc中成功编写了一些内联汇编器,以向右旋转一位
遵循一些不错的指示:http://www.cs.dartmouth.edu/~sergey/cs108/2009/gcc-inline-asm.pdf

这是一个例子:
static inline int ror(int v) {
    asm ("ror %0;" :"=r"(v) /* output */ :"0"(v) /* input */ );
    return v;
}

但是,我希望代码计数时钟周期,并且已经看到一些错误的(可能是Microsoft)格式。我不知道如何在gcc中执行这些操作。有什么帮助吗?
unsigned __int64 inline GetRDTSC() {
   __asm {
      ; Flush the pipeline
      XOR eax, eax
      CPUID
      ; Get RDTSC counter in edx:eax
      RDTSC
   }
}

我试过了:
static inline unsigned long long getClocks() {
    asm("xor %%eax, %%eax" );
    asm(CPUID);
    asm(RDTSC : : %%edx %%eax); //Get RDTSC counter in edx:eax

但是我不知道如何让edx:eax对干净地返回64位,也不知道如何真正刷新管道。

另外,我发现的最佳源代码是:http://www.strchr.com/performance_measurements_with_rdtsc

那就是提到奔腾,因此,如果在不同的intel / AMD变体上有不同的处理方式,请告诉我。我希望在所有x86平台上都可以使用的东西(即使有点难看),而不是为每个变体提供一系列解决方案,但是我不介意对此有所了解。

最佳答案

以下是您想要的:

inline unsigned long long rdtsc() {
  unsigned int lo, hi;
  asm volatile (
     "cpuid \n"
     "rdtsc"
   : "=a"(lo), "=d"(hi) /* outputs */
   : "a"(0)             /* inputs */
   : "%ebx", "%ecx");     /* clobbers*/
  return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
}

重要的是,在代码中放置尽可能少的内联ASM,因为它会阻止编译器进行任何优化。这就是为什么我用C代码而不是用ASM进行结果的移位和运算。同样,我使用0的“a”输入让编译器决定何时以及如何将eax归零。可能是程序中的某些其他代码已将其清零,并且编译器可以在知道的情况下保存一条指令。

同样,上面的“掩饰”也很重要。 CPUID覆盖eax,ebx,ecx和edx中的所有内容。您需要告诉编译器您正在更改这些寄存器,以便它知道不要在其中保留任何重要内容。您不必列出eax和edx,因为您将它们用作输出。如果您没有列出这些问题,则很可能会导致程序崩溃,并且很难找到问题所在。

07-24 09:45
查看更多