本文将汇总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
|