深入理解计算机系统--测量程序执行时间

理论基础

在进行系统时间获取并用于程序性能分析时,我们需要考虑精确而有效的时间获取方法。

在《深入理解计算机系统》这本书中谈到,目前进行时间测量的系统接口和方法有两种:

    通过间隔计数的方法:

        OS维护着每个进程使用的用户时间量和系统时间量的计数值,当计时器中断发生时,OS会确定哪个进程是活动的,并且对那个进程的一个计数值增加计时器间隔时间。这时会根据进程的状态,如果是内核态就增加系统时间,否则增加用户时间。

        这种计时方式并不管在这个时间段(两个计时器中断之间)内到底用了多少时间,所以不够准确。但是从长时间考虑,这个平均值还是可以接受的。

    利用周期计数器的方法:

        很多CPU包含了一个运行在时钟周期级的计时器。这个计时器其实是个特殊的寄存器,每个时钟周期会加1。这个工具可以用来测量一个程序执行中两个不同点之间经过的时间。就是基于系统时间点的测量,而在这两点之间的情况并不关心。这样导致了多任务系统上,这种计时器只能用于对比而无法直接表示进程时间消耗。所以其受上下文切换、高速缓存的影响。

通过上面的比较和介绍,我们可以看到,两种方法各有优劣、是从不同的方向来进行时间测量的。

所以,这本书在章节后面给出了一个协议:

    如果程序X预期的运行时间很长(运行时间远远大于间隔计数的时间段),可以使用间隔计数的方式。

    如果X预期运行时间大概在0.01~1.0s之间,那么在负载很轻的系统上,就需要使用周期计时的方式。在这里强调负载轻,主要原因是害怕上下文切换等因素的影响。

    如果X预期运行时间小于0.01s,那么就使用周期计时的方式。这时候,由于时间很短,不用担心负载问题,上下文切换等因素起到的影响就很小了。

下面分析我们通常使用的:

-----------------------------------

clock_gettime:

    .save   {r4, r7}

    stmfd   sp!, {r4, r7}

    ldr     r7, =__NR_clock_gettime

    swi     #0

    ldmfd   sp!, {r4, r7}

    movs    r0, r0

    bxpl    lr

    b       __set_syscall_errno

    .fnend

-----------------------------------

gettimeofday:

    .save   {r4, r7}

    stmfd   sp!, {r4, r7}

    ldr     r7, =__NR_gettimeofday

    swi     #0

    ldmfd   sp!, {r4, r7}

    movs    r0, r0

    bxpl    lr

    b       __set_syscall_errno

    .fnend

-----------------------------------

这两个函数都是直接进行了系统调用。

关于时间源这类的时间调用是复杂的,我也没有做这方面工作的经验,不敢乱言。

使用说明请参考: http://www.360doc.com/content/11/0715/09/1317564_133662142.shtml

gettimeofday()提供了微秒级的精确度  

    1、头文件 <time.h>  

    2、函数原型  

    int gettimeofday(struct timeval *tv, struct timezone *tz);   

    gettimeofday()会把目前的时间由tv所指的结构返回,当地时区的信息则放到tz所指的结构中(可用NULL)。  

    参数说明:  

        timeval结构定义为:  

        struct timeval  

        {  

            long tv_sec; /*秒*/  

            long tv_usec; /*微秒*/  

        };  

        timezone 结构定义为:  

        struct timezone  

        {  

            int tz_minuteswest; /*和Greenwich 时间差了多少分钟*/  

            int tz_dsttime; /*日光节约时间的状态*/  

        };  

        上述两个结构都定义在/usr/include/sys/time.h。tz_dsttime 所代表的状态如下  

            DST_NONE /*不使用*/  

            DST_USA /*美国*/  

            DST_AUST /*澳洲*/  

            DST_WET /*西欧*/  

            DST_MET /*中欧*/  

            DST_EET /*东欧*/  

            DST_CAN /*加拿大*/  

            DST_GB /*大不列颠*/  

            DST_RUM /*罗马尼亚*/  

            DST_TUR /*土耳其*/  

            DST_AUSTALT /*澳洲(1986年以后)*/  

    返回值: 成功则返回0,失败返回-1,错误代码存于errno。附加说明EFAULT指针tv和tz所指的内存空间超出存取权限。  

    #include<stdio.h>  

    #include<time.h>  

    int main(void)  

    {  

        struct timeval tv;  

        struct timezone tz;  

        gettimeofday (&tv , &tz);  

        printf(“tv_sec; %d/n”, tv,.tv_sec) ;  

        printf(“tv_usec; %d/n”,tv.tv_usec);  

        printf(“tz_minuteswest; %d/n”, tz.tz_minuteswest);  

        printf(“tz_dsttime, %d/n”,tz.tz_dsttime);  

        return 0;  

    }  

clock_gettime( ) 提供了纳秒级的精确度  

    1、头文件 <time.h>  

    2、编译&链接。在编译链接时需加上 -lrt ;因为在librt中实现了clock_gettime函数  

    3、函数原型  

    int clock_gettime(clockid_t clk_id, struct timespect *tp);  

        参数说明:  

        clockid_t clk_id 用于指定计时时钟的类型,有以下4种:  

            CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户该成其他,则对应的时间相应改变  

            CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响  

            CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间  

            CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统CPU花费的时间  

        struct timespect *tp用来存储当前的时间,其结构如下:  

            struct timespec  

            {  

                time_t tv_sec; /* seconds */  

                long tv_nsec; /* nanoseconds */  

            };  

        返回值。0成功,-1失败  

    #include<stdio.h>  

    #include<time.h>  

    int main()  

    {  

        struct timespec ts;  

        clock_gettime(CLOCK_REALTIME, &ts);  

        printf("CLOCK_REALTIME: %d, %d", ts.tv_sec, ts.tv_nsec);  

        clock_gettime(CLOCK_MONOTONIC, &ts);//打印出来的时间跟 cat /proc/uptime 第一个参数一样  

        printf("CLOCK_MONOTONIC: %d, %d", ts.tv_sec, ts.tv_nsec);  

        clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);  

        printf("CLOCK_PROCESS_CPUTIME_ID: %d, %d", ts.tv_sec, ts.tv_nsec);  

        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);  

        printf("CLOCK_THREAD_CPUTIME_ID: %d, %d", ts.tv_sec, ts.tv_nsec);  

        printf("/n%d/n", time(NULL));  

        return 0;  

    }  

    /proc/uptime里面的两个数字分别表示:   

    the uptime of the system (seconds), and the amount of time spent in idle process (seconds).   

    把第一个数读出来,那就是从系统启动至今的时间,单位是秒  


猜你喜欢

转载自qianjigui.iteye.com/blog/1485939