粉丝想计算一个函数的执行时间。

函数的执行时间的统计在嵌入式系统中会被频繁地用到,知识点很重要。 本文从两个方面来讨论类似的问题:
- 程序内计算一个函数的执行时间
- 计算一个程序的执行时间
我们在执行函数前后分别记录下时间戳,然后计算两个时间戳的差值即可。
我们需要借助函数clock_gettime来实现这个功能。 看下该函数的定义:
#includetime.hintclock_gettime(clockid_t clk_id,structtimespec* tp);可以根据需要,获取不同要求的精确时间参数:clk_id : 检索和设置的clk_id指定的时钟时间。CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-10:0:0开始计时,中间时刻如果系统时间被用户改成其他,则对应的时间相应改变CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统CPU花费的时间tp : 获取的时间戳会存放到该结构体变量中structtimespec { time_t tv_sec;/* 秒*/longtv_nsec;/* 纳秒*/};返回值: 成功0失败-1,同时errno会被赋值
因为我们希望计算执行某个函数的时间,所以我们第一个参数选择CLOCK_MONOTONIC。
我们先来实现一个简单的程序:
19行 我们可以将自己要执行的函数放置在此处。
编译
gccruntime.c-lrt
注意需要增加动态链接库lrt,函数clock_gettime()定义于该库中。
执行结果如下:
第一个实例比较简单,实际在应用中,尤其是在网络通信中,经常需要计算收发数据包的总共时间,以网络的速率。 现在我们增加功能如下:
- 检查执行函数前后的时间戳合法性,因为有时候记录的时间会比较长,会有数据溢出等问题
- 循环累加总共执行时间,计算总共执行时间,然后根据执行次数计算平均执行时间
- timespec_check()
staticint timespec_check(structtimespec*t){if((t-tv_nsec0) || (t-tv_nsec =1000000000))return-1;return0;}功能: 该函数检查时间戳的成员tv_nsec,该值不能小于0,也不能大于1000000000参数: t 时间戳返回值 成功返回0非法返回-1
- timespec_sub()
staticvoid timespec_sub(structtimespec*t1,structtimespec*t2){if(timespec_check(t1)0) { fprintf(stderr,"invalid time #1: %lld.%.9ld.", t1-tv_sec,t1-tv_nsec);return; }if(timespec_check(t2)0) { fprintf(stderr,"invalid time #2: %lld.%.9ld.", t2-tv_sec,t2-tv_nsec);return; } t1-tv_sec -= t2-tv_sec; t1-tv_nsec -= t2-tv_nsec;if(t1-tv_nsec =1000000000) {//tv_nsec 超过1000000000,秒需要加1t1-tv_sec++; t1-tv_nsec -=1000000000; }elseif(t1-tv_nsec0) {//tv_nsec 小于0,秒需要减1t1-tv_sec--; t1-tv_nsec +=1000000000; }}功能: 该函数首先检查参数t1、t2合法性,然后用t1的时间减去t2的时间,并把结果存放到t1参数: t1:对应函数执行执行结束的时间 t2:对应函数执行之前的时间返回值: 无
编译执行如下:
有时候我们还想知道执行某个程序需要多少时间,我们可以借助命令time。
Linux time命令的用途,在于量测特定指令执行时所需消耗的时间及系统资源等信息。
CPU资源的统计包括实际使用时间、用户态使用时间、内核态使用时间。
time[options]COMMAND[arguments]
- 在以上实例中,执行命令"time date"(见第1行)。
- 系统先执行命令"date",第2行为命令"date"的执行结果。
- 第3-6行为执行命令"date"的时间统计结果,其中第4行"real"为实际时间,第5行"user"为用户CPU时间,第6行"sys"为系统CPU时间。 以上三种时间的显示格式均为MMmNN[.FFF]s。
我们也可以测试上一章我们编写的程序:
下面我们将59行代码中的usleep(200)修改成sleep(1) 重新编译执行,10秒回打印如下执行结果:
大家可以根据我的代码,方便地将该功能移植到自己的项目中。