如何在c编程中使用rdtsc来估计for循环的开销

我想在0到7的范围内增加参数来计算参数的开销。 如何估算硬件开销和软件开销。

你的问题不是很好。 但是,执行rdtsc指令最可靠的方法是用内联汇编调用它,这是所有C编译器完全支持的。 由C标准规定的任何定时功能将根据实现而变化。 英特尔有一个非常好的关于在这里实现rdtsc的最佳方式的rdtsc 。 主要的问题是乱序执行,这可能超出了你的问题的范围。

我发现的最好的实现是在这个回购 ,我已经适应了我自己的使用。 假设你有一个兼容的处理器,这个基本的宏组合将给你每个通话开销32个时钟周期(你需要为自己的处理器测试):

 #include <cpuid.h> #include <stdint.h> /*** Low level interface ***/ /* there may be some unnecessary clobbering here*/ #define _setClockStart(HIs,LOs) { \ asm volatile ("CPUID \n\t" \ "RDTSC \n\t" \ "mov %%edx, %0 \n\t" \ "mov %%eax, %1 \n\t": \ "=r" (HIs), "=r" (LOs):: \ "%rax", "%rbx", "%rcx", "%rdx"); \ } #define _setClockEnd(HIe,LOe) { \ asm volatile ("RDTSCP \n\t" \ "mov %%edx, %0 \n\t" \ "mov %%eax, %1 \n \t" \ "CPUID \n \t": "=r" (HIe), "=r" (LOe):: \ "%rax", "%rbx", "%rcx", "%rdx"); \ } #define _setClockBit(HIs,LOs,s,HIe,LOe,e) { \ s=LOs | ((uint64_t)HIs << 32); \ e=LOe | ((uint64_t)HIe << 32); \ } 

 /*** High level interface ***/ typedef struct { volatile uint32_t hiStart; volatile uint32_t loStart; volatile uint32_t hiEnd; volatile uint32_t loEnd; volatile uint64_t tStart; volatile uint64_t tEnd; /*tend-tstart*/ uint64_t tDur; } timer_st; #define startTimer(ts) \ { \ _setClockStart(ts.hiStart,ts.loStart); \ } #define endTimer(ts) \ { \ _setClockEnd(ts.hiEnd,ts.loEnd); \ _setClockBit(ts.hiStart,ts.loStart,ts.tStart, \ ts.hiEnd,ts.loEnd,ts.tEnd); \ ts.tDur=ts.tEnd-ts.tStart; \ } #define lapTimer(ts) \ { \ ts.hiStart=ts.hiEnd; \ ts.loStart=ts.loEnd; \ } 

然后用这样的东西来调用它

 #include <stdio.h> #include <math.h> #include "macros.h" /* Macros for calling rdtsc above */ #define SAMPLE_SIZE 100000 int main() { timer_st ts; register double mean=0; register double variance=0; int i; /* "Warmup" */ for(i=1;i<SAMPLE_SIZE;i++) { startTimer(ts); endTimer(ts); } /* Data collection */ for(i=1;i<SAMPLE_SIZE;i++) { startTimer(ts); endTimer(ts); mean+=ts.tDur; } mean/=SAMPLE_SIZE; fprintf(stdout,"SampleSize: %d\nMeanOverhead: %f\n", SAMPLE_SIZE,mean); return 0; } 

在我的Broadwell芯片上,我得到了这个输出

 SampleSize: 100000 MeanOverhead: 28.946490 

29时钟抽搐的时钟分辨率是相当不错的。 人们典型使用的任何库函数(如gettimeofday )都不具备时钟级准确性和开销〜200-300。

我不确定“硬件开销”与“软件开销”是什么意思,但是对于上面的实现,没有函数调用来完成rdtsc调用之间的时间和中间代码。 所以我想软件开销是零。

首先要做的就是disassembly ,在Linux上你可以从objdump帮助。 objdump将帮助您查看代码是如何生成的。 如果你对这些传递的参数没有做任何处理,那就是从堆栈中取参数并保存在一个寄存器上的区别。 由于这些mov操作将花费很少的cpu周期,因此很难提供时序信息,但是CPU周期更加容易。