标签归档:周期计数器

测量程序执行时间-周期计数器

摘自“深入理解计算机系统”
测量程序执行时间-周期计数器
为了给计时测量提供更高的精确度,许多处理器还包含一个运行在时钟周期级的计时器。这个计时器是一个特殊的寄存器,每个时钟周期它会都会加1.可以用特殊的机器指令来读取这个计数器的值。不是所有的处理器都有这样的计数器的,而且有这样的计数器的处理器在实现细节上也各不相同。因此,程序猿无法用统一的、与平台无关的接口使用这些计数器。另一方面,只用少量的汇编代码,通常很容易就为某个特定的机器创建一个程序接口。
IA32周期计数器
到目前为止,我们已经报告的所有计时值都是用IA32周期计数器测量出来的。在IA32体系结构中,周期计数器是与P6微体系机构一起提出来的。周期计数器是一个64位无符号数。对于一个运行时钟为1GHz的处理器,只是在每1.8 * 10的10次方 或者每 570年,这个计数器才会从2的64次方-1绕回到0.另一方面,如果我们只考虑这个计数器的低32位,把它看成一个无符号整数,那么这个值大约每4.3秒就绕回。因此,我们就明白了为什么IA32的设计者会决定实现一个64位的计数器。
IA32计数器是用rdtsc(read time stamp counter,读时间戳计数器)指令来访问的。这条指令没有参数,它将寄存器%edx设置为计数器的高32位,而寄存器%eax设置为低32位,为了提供一个C程序接口,我们想把这个指令包装到一个过程中;
void access_counter(unsigned *hi,unsigned *lo);
这个过程应该将位置hi设置为计数器的高32位,将lo设置为低32位。

static unsigned cyc_hi =0;
static unsigned cyc_lo =0;

void access_counter(unsigned *hi,unsigned *lo)
{
asm(“rdtsc; movl %%edx,%0; movl %%eax,%l”
:”=r” (*hi), “=r” (*lo)
:
:”%edx”, “%eax”
);
}

void start_counter()
{
access_counter(&cyc_hi,&cyc_lo);
}

double get_counter()
{
unsigned ncyc_hi,ncyc_lo;
unsigned hi,lo,borrow;
double result;

access_counter(&ncyc_hi,&ncyc_lo);
lo = ncyc_lo-cyc_lo;
borrow =lo>ncyc_lo;
hi =ncyc_hi-cyc_hi-borrow;
result =(double)hi *(1<<30)*4+lo; if(result <0) { fprintf(stderr,"error:%0f",result); } return result; } 上面的函数可以测量两个时间点之间的时钟周期总数。