本文将汇总Linux用户态程序获取时间的接口,本文内容主要转载自clock()、time()、clock_gettime()和gettimeofday()函数的用法和区别 。
1. clock() https://man7.org/linux/man-pages/man3/clock.3.html
1.1 概述 clock
函数的返回值类型是clock_t
,它除以CLOCKS_PER_SEC
来得出时间,一般用两次clock
函数来计算进程自身运行的时间.
clock
有三个问题:
如果超过一个小时,将要导致溢出.
函数clock
没有考虑CPU被子进程使用的情况.
也不能区分用户空间和内核空间.
所以clock
函数在linux系统上变得没有意义.
1.2 测试 编写程序,测试采用clock
函数的输出与time
程序的区别.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> #include <stdlib.h> #include <time.h> int main ( void ) { long i=1000L ; clock_t start, finish; double duration; printf ( "Time to do %ld empty loops is " , i ); start = clock(); while (--i){ system("cd" ); } finish = clock(); duration = (double )(finish - start) / CLOCKS_PER_SEC; printf ( "%f seconds\n" , duration ); return 0 ; }
1 2 3 4 5 6 7 $ gcc test1.c -o test1 $ time ./test1 Time to do 1000 empty loops is 0.180000 seconds real 0m3.492s user 0m0.512s sys 0m2.972s
1.3 总结
程序调用system("cd")
,这里主要是子进程的消耗,test1程序不能体现这一点.
0.180000 seconds秒的消耗是两次clock()
函数调用除以CLOCKS_PER_SEC
.
clock()
函数返回值是一个相对时间,而不是绝对时间.
CLOCKS_PER_SEC
是系统定义的宏,由GNU标准库定义为1000000.
2. times() https://man7.org/linux/man-pages/man2/times.2.html
2.1 概述 原型如下:clock_t times(struct tms *buf);
tms结构体如下:1 2 3 4 5 6 struct tms { clock_t tms_utime; clock_t tms_stime; clock_t tms_cutime; clock_t tms_cstime; }
tms_utime
记录的是进程执行用户代码的时间.tms_stime
记录的是进程执行内核代码的时间.tms_cutime
记录的是子进程执行用户代码的时间.tms_cstime
记录的是子进程执行内核代码的时间.
2.2 测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <sys/times.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> static void do_cmd (char *) ;static void pr_times (clock_t , struct tms *, struct tms *) ;int main (int argc, char *argv[]) { int i; for (i=1 ; argv[i]!=NULL ; i++){ do_cmd(argv[i]); } exit (1 ); } static void do_cmd (char *cmd) { struct tms tmsstart , tmsend ; clock_t start, end; int status; if ((start=times(&tmsstart))== -1 ) puts ("times error" ); if ((status=system(cmd))<0 ) puts ("system error" ); if ((end=times(&tmsend))== -1 ) puts ("times error" ); pr_times(end-start, &tmsstart, &tmsend); exit (0 ); } static void pr_times (clock_t real, struct tms *tmsstart, struct tms *tmsend) { static long clktck=0 ; if (0 == clktck) if ((clktck=sysconf(_SC_CLK_TCK))<0 ) puts ("sysconf err" ); printf ("real:%7.2f\n" , real/(double )clktck); printf ("user-cpu:%7.2f\n" , (tmsend->tms_utime - tmsstart->tms_utime)/(double )clktck); printf ("system-cpu:%7.2f\n" , (tmsend->tms_stime - tmsstart->tms_stime)/(double )clktck); printf ("child-user-cpu:%7.2f\n" , (tmsend->tms_cutime - tmsstart->tms_cutime)/(double )clktck); printf ("child-system-cpu:%7.2f\n" , (tmsend->tms_cstime - tmsstart->tms_cstime)/(double )clktck); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ gcc test2.c -o test2 $ time ./test2 "dd if=/dev/zero f=/dev/null bs=1M count=10000" 10000+0 records in 10000+0 records out 10485760000 bytes (10 GB) copied, 4.93028 s, 2.1 GB/s real: 4.94 user-cpu: 0.00 system-cpu: 0.00 child-user-cpu: 0.01 child-system-cpu: 4.82 real 0m4.943s user 0m0.016s sys 0m4.828s
2.3 总结
通过这个测试,系统的time
程序与test2程序输出基本一致了.
(double)clktck
是通过clktck=sysconf(_SC_CLK_TCK)
来取的,也就是要得到user-cpu所占用的时间,就要用(tmsend->tms_utime - tmsstart->tms_utime)/(double)clktck)
clock_t times(struct tms *buf)
返回值是过去一段时间内时钟嘀嗒的次数.
times()
函数返回值也是一个相对时间.
3. gettimeofday() https://man7.org/linux/man-pages/man2/gettimeofday.2.html
3.1 概述 gettimeofday()
可以获得当前系统的时间,是一个绝对值
原型如下:int gettimeofday (struct timeval * tv , struct timezone * tz)
timeval
结型体的原型如下:1 2 3 4 struct timeval { time_t tv_sec; suseconds_t tv_usec; };
所以它可以精确到微秒
3.2 测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <sys/time.h> #include <stdio.h> #include <unistd.h> int main(){ int i=10000000 ; struct timeval tvs ,tve ; gettimeofday(&tvs,NULL ); while (--i); gettimeofday(&tve,NULL ); double span = tve.tv_sec-tvs.tv_sec + (tve.tv_usec-tvs.tv_usec)/1000000.0 ; printf ("time: %.12f\n" ,span); return 0 ; }
1 2 3 $ gcc test5.c $ ./a.out time: 0.041239000000
4. clock_gettime() https://www.man7.org/linux/man-pages/man3/clock_gettime.3.html
4.1 概述 原型如下:int clock_gettime(clockid_t clk_id, struct timespec *tp);
有以下特点:
有一个时间结构体:timespec
,timespec
计算时间的精度是ns.
1 2 3 4 struct timespec { time_t tv_sec; long tv_nsec; }
clockid_t
确定哪个时钟类型.CLOCK_REALTIME
CLOCK_MONOTONIC
CLOCK_PROCESS_CPUTIME_ID
和CLOCK_THREAD_CPUTIME_ID
.
4.2 测试: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <time.h> #include <stdio.h> #include <stdlib.h> #define MILLION 1000000 int main (void ) { long int loop = 1000 ; struct timespec tpstart ; struct timespec tpend ; long timedif; clock_gettime(CLOCK_MONOTONIC, &tpstart); while (--loop){ system("cd" ); } clock_gettime(CLOCK_MONOTONIC, &tpend); timedif = MILLION*(tpend.tv_sec-tpstart.tv_sec)+(tpend.tv_nsec-tpstart.tv_nsec)/1000 ; fprintf (stdout , "it took %ld microseconds\n" , timedif); return 0 ; }
1 2 3 4 5 6 7 8 $ gcc test3.c -lrt -o test3 $ time ./test3 it took 3463843 microseconds real 0m3.467s user 0m0.512s sys 0m2.936s
5. 比较 5.1 精度
clock()
的精度是10毫秒(ms)
times()
的精度是10毫秒(ms)
gettimofday()
的精度是微秒(μs)
clock_gettime()
的精度是纳秒(ns)
5.2 测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <sys/times.h> #include <sys/time.h> #define WAIT for(i=0;i<298765432;i++); #define MILLION 1000000 int main ( int argc, char *argv[] ) { int i; long ttt; clock_t s,e; struct tms aaa ; s=clock(); WAIT; e=clock(); printf ("clock time : %.12f\n" ,(e-s)/(double )CLOCKS_PER_SEC); long tps = sysconf(_SC_CLK_TCK); s=times(&aaa); WAIT; e=times(&aaa); printf ("times time : %.12f\n" ,(e-s)/(double )tps); struct timeval tvs ,tve ; gettimeofday(&tvs,NULL ); WAIT; gettimeofday(&tve,NULL ); double span = tve.tv_sec-tvs.tv_sec + (tve.tv_usec-tvs.tv_usec)/1000000.0 ; printf ("gettimeofday time: %.12f\n" ,span); struct timespec tpstart ; struct timespec tpend ; clock_gettime(CLOCK_REALTIME, &tpstart); WAIT; clock_gettime(CLOCK_REALTIME, &tpend); double timedif = (tpend.tv_sec-tpstart.tv_sec)+(tpend.tv_nsec-tpstart.tv_nsec)/1000000000.0 ; printf ("clock_gettime time: %.12f\n" , timedif); return EXIT_SUCCESS; }
1 2 3 4 5 6 $ gcc -lrt test4.c -o test4 $ ./test4 clock time : 1.190000000000 times time : 1.180000000000 gettimeofday time: 1.186477000000 clock_gettime time: 1.179271718000