在我的程序中使用rdtsc()来获得单字和双字操作的时钟周期数?

时间:2016-04-14 13:07:31

标签: c gcc rdtsc

理论上,双字加法/减法的成本是单字的2倍。类似地,单字乘法与加法的成本比被视为3.我在Ubuntu LTS 14.04上使用GCC编写了以下C程序,以检查我的机器上的时钟周期数,Intel Sandy Bridge Corei5-2410M。虽然,大多数情况下程序返回6个时钟周期进行128位加法,但我采取了最好的情况。我使用命令编译(gcc -o ow -O3 cost.c),结果在下面给出

32-bit Add: Clock cycles = 1    64-bit Add: Clock cycles = 1    64-bit Mult: Clock cycles = 2   128-bit Add: Clock cycles = 5 

该计划如下:

#define n 500
#define counter 50000

typedef uint64_t utype64;
typedef int64_t type64;
typedef __int128 type128;

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

int main(){
    utype64 start, end;
    type64 a[n], b[n], c[n];
    type128 d[n], e[n], f[n];
    int g[n], h[n];
    unsigned short i, j;
    srand(time(NULL));
    for(i=0;i<n;i++){ g[i]=rand(); h[i]=rand(); b[i]=(rand()+2294967295); e[i]=(type128)(rand()+2294967295)*(rand()+2294967295);}
    for(j=0;j<counter;j++){
       start=rdtsc();
       for(i=0;i<n;i++){ a[i]=(type64)g[i]+h[i]; }
       end=rdtsc();
       if((j+1)%5000 == 0)
          printf("%lu-bit Add: Clock cycles = %lu \t", sizeof(g[0])*8, (end-start)/n);

       start=rdtsc();
       for(i=0;i<n;i++){ c[i]=a[i]+b[i]; }
       end=rdtsc();
       if((j+1)%5000 == 0)
          printf("%lu-bit Add: Clock cycles = %lu \t", sizeof(a[0])*8, (end-start)/n);

       start=rdtsc();
       for(i=0;i<n;i++){ d[i]=(type128)c[i]*b[i]; }
       end=rdtsc();
       if((j+1)%5000 == 0)
          printf("%lu-bit Mult: Clock cycles = %lu \t", sizeof(c[0])*8, (end-start)/n);

       start=rdtsc();
       for(i=0;i<n;i++){ f[i]=d[i]+e[i]; }
       end=rdtsc();
       if((j+1)%5000 == 0){
          printf("%lu-bit Add: Clock cycles = %lu \n", sizeof(d[0])*8, (end-start)/n);
        printf("f[%hu]= %ld %ld \n\n", i-7, (type64)(f[i-7]>>64), (type64)(f[i-7]));}
   }

return 0;
}

结果中有两件事困扰着我。

1)(64位)乘法的时钟周期数可以变为2吗?

2)为什么双字加法的时钟周期数超过单字加法的2倍?

我主要关注案例(2)。现在,问题出现了,因为我的程序逻辑?或者是由于GCC编译器优化?

1 个答案:

答案 0 :(得分:2)

  

理论上我们知道双字加法/减法需要2倍的单字。

不,我们没有。

  

同样,由于CPU的快速整数乘数,单字乘法与加法的成本比为3。

不,不是。

你没有测量说明。您正在测量程序中的语句。哪个与编译器将发出的指令有任何关系,也可能没有。例如,我的编译器在修复代码以便编译之后,将一些循环向量化。每条指令添加多个值。第一个循环本身仍然是23个指令长,并且仍然由您的代码报告为1个循环。

Modern(与过去25年一样)CPU一次不执行一条指令。他们将立即在飞行中有多个指令,并且可以不按顺序执行它们。

然后你有内存访问。在CPU上没有可以从内存中获取值的指令,将其从内存中添加到另一个值,然后将其存储在第三个内存位置。因此必须已经执行了多个指令。此外,内存访问的成本远远超过算术指令,任何接触内存的东西(除非它一直打到L1缓存)将受内存访问时间的支配。

此外,RDTSC甚至可能不会返回实际的循环计数。某些CPU具有可变时钟速率但仍然保持TSC以相同的速率运行,无论CPU实际运行的速度有多快或多慢,因为操作系统使用TSC进行计时。其他人没有。

所以,你没有衡量你认为自己在衡量的是什么,也没有人告诉你这些事情要么过于简单化,要么在二十年内没有看过CPU文档。