标签归档:测量程序执行时间

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

摘自“深入理解计算机系统”
周期计数器如何测量程序的执行时间
周期计数器提供了一个非常精确的工具,可以测量一个程序执行中两个不同点之间经过的时间。我们的周期计数器通过在程序中调用start_counter 和调用get_counter之间总的周期数。这些程序不记录那些进程使用了这个周期,只记载了这个计数器开始和结束的位置,并取两个之差作为周期计数器测量程序执行时间。
例:测量某个程序P的运行时间的一种简单方法就是用周期计数器对P的一次执行进行记时,如下代码所示:
double time_P(){
start_counter(); // 开始计数器
P(); //开始运行程序P
return get_counter(); //返回计数器时间
}
如果在这两次调用计数器里面,有其它的另外进程执行,那么这段代码就很容易产生令人误解的结果。如果机器负载很重,或者如果P的运行时间特别长,那么这个get_counter检测出的程序运行时间都是同实际正常值存在较大差异。
如何将高速缓存对测量程序的执行时间的影响?我们需要在程序开始时,加上P(),把程序加载到高速缓存中
double time_p(){
P();
start_counter(); // 开始计数器
P(); //开始运行程序P
return get_counter(); //返回计数器时间
}

我们可以看出,周期计数器需要进行N次测量,然后通过取n次近似值,来预估程序的执行时间。

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

摘自“深入理解计算机系统”
测量程序执行时间-周期计数器
为了给计时测量提供更高的精确度,许多处理器还包含一个运行在时钟周期级的计时器。这个计时器是一个特殊的寄存器,每个时钟周期它会都会加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; } 上面的函数可以测量两个时间点之间的时钟周期总数。

测量程序执行时间-通过间隔计数器time测量时间

摘自“深入理解计算机系统”
操作系统也用计时器来记录每个进程使用的累积时间,这种信息提供的是对程序执行时间不那么准确的测量值。
操作系统维护着每个进程使用的用户时间量和系统时间量的计数值,当计时器中断发生时,操作系统会确定哪个进程是活动,并且对那个进程的一个计数值增加计时器间隔时间。如果系统时在内核模式中运行的,那么就增加系统时间,否则就增加用户时间。
读进程的计时器
在linux或unix 中可以通过time 来测量命令的执行时间。这个命令使用的值是用操作系统的计时器方法计算出来的系统执行时间。
例:[root@localhost ~]#time ./jiaFa -n 17 //可以打印出运行t1.o所需的时间 以及系统运行在用户模式和内核模式的时间。

time -n 17

time -n 17


从图片中可以看出 第一行是总时间 中间包含中断运行其它程序所用的时间 第二和第三 分别是系统时间和用户时间。