如何在代码中计算代码执行的时钟周期数

 有的时候,需要在代码中获取代码运行的时钟周期数。那么,怎么获取到某段代码在运行时的时钟周期数呢?

通过获取程序运行时间

 在代码中直接计算一个程序的时钟周期是不容易的。但是计算一个程序的执行时间却是比较容易的。编程语言和操作系统都提供有相关的封装好的接口,可以很方便地调用来得到程序的运行时间。这方面的参考资料很多,我就不去介绍了。

 如何获取程序的执行时间? Linux环境 || Windows环境

 下面来介绍一下怎么通过获取的程序执行时间来得到十周周期数。
 CPU时钟周期:通常为节拍脉冲或T周期,即主频的倒数,它是CPU中最小的时间单位,每个动作至少需要一个时钟周期。而主频又与与具体的时间有关。CPU的主频表示每秒进行的时钟周期数。那么运行时间与时钟周期数有如下的计算方式:

 根据获取的运行时间和CPU的主频可以计算出程序的时钟周期数。

直接计算时钟周期数

 也有直接计算时钟周期数的方法。为了给计时测量提供更高的准确度,很多处理器还包含一个运行在始终周期级别的计时器,它是一个特殊的寄存器,每个时钟周期它都会自动加1。这个周期计数器呢,是一个64位无符号数,直观理解,就是如果你的处理器是1GHz的,那么需要570年,它才会从2的64次方绕回到0,所以你大可不必考虑溢出的问题。但是这种方法是依赖于硬件的。首先,并不是每种处理器都有这样的寄存器的;其次,即使大多数都有,实现机制也不一样,因此,我们无法用统一的,与平台无关的接口来使用它们。于是就要使用汇编来处理。在这里给出一个C语言嵌入汇编的例程。

unsigned long long int begin,end,total=0;	
static __inline__ unsigned long long rdtsc(void)
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo),"=d"(hi));
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}

int main(){
begin=rdtsc();

//这里调用要测试的函数
end=rdtsc();
total = end – begin; // total即為 cpu clock cycle
}

存在的问题

对于第一种方法

 对于先计时再计算时钟周期数,除开计时器本身可能存在的精度问题。另外,时间 = 周期数 / 频率,由于频率可能会变(比如我的笔记本的 CPU 通常半速运行在 800MHz,繁忙的时候全速运行在 1.6GHz),那么测得的时间也就不准确了。计算的时钟周期就不准。

对于第二种方法

原文链接

 在多核时代,RDTSC 指令的准确度大大削弱了,原因有三:

  • 不能保证同一块主板上每个核的 TSC 是同步的;
  • CPU 的时钟频率可能变化,例如笔记本电脑的节能功能;
  • 乱序执行导致 RDTSC 测得的周期数不准,这个问题从 Pentium Pro 时代就存在。

 在多核下,这两次执行可能会在两个CPU上发生,而这两个CPU的计数器的初值不一定相同(由于完成上电复位的准确时机不同),(有办法同步,见如何同步),那么就导致结果包含了这个误差,这个误差可正可负,取决于先执行的那块CPU 的时钟计数器是超前还是落后。

&emsp乱序执行这个问题比较简单,但意义深远。在现代 CPU 的复杂架构下,测量几条或几十条指令的耗时是无意义的,因为观测本身会干扰 CPU 的执行(cache, 流水线, 多发射,乱序, 猜测)。要么我们以更宏观的指标来标示性能;要么用专门的手段来减小对观测结果的影响。

 当然,无论怎样,都不可能测得一个程序的准确时钟周期数。但是在允许一定误差存在的条件下,这些方法是有效的,根据场景合理的选择需要的方法。