real time、CPU time探讨

APUE 3.9节中关于系统调用read给出了不同大小的缓冲区会导致读取效率的差异。这里stevens用三种时间表示读取文件过程所花费的时间。这三种时间分别为真实/时钟时间(real / clock time),系统cpu时间(system cpu time),用户cpu时间(user cpu time )。其意义如下:
         真实时间:进程从开始执行到最后结束的时间,包括阻塞+就绪(排队等待)+运行的时间。也即我们能够真实感受到的时间。
         系统cpu时间:进程运行时,在系统区执行的时间,如(write,read等系统调用),运行的地方位于系统内存中。
         用户cpu时间:进程运行时,在用户区执行的时间。这里主要是我们自己编写的代码,运行在用户内存中。

程序从用户态到系统态需要消耗一定的时间,频繁的切换会导致系统运行的效率低下。但缓冲区又不宜太大,浪费用户内存。所以合适的缓冲区大小很有必要。那我们如何确定一个最佳的缓冲区呢?stevens就用上面的三种时间去测试系统效率。他选用的bufsize从1,2,4,8 ... 524888 这20个值进行测试,最后得出最佳大小。那我们如何获得这些时间呢?

其实linux提供了很多关于时间的系统调用,如time,gettimeofday,clock,times等等。其中前三个很常用,但无法获得system cpu time 和 user cpu time。所以这里主要介绍times函数。它的函数原型为:

[cpp]  view plain  copy
  1. #include<sys/times>  
  2. clock_t times(struct  tms * buf);  
  3. struct tms  的成员结构如下:  
  4. struct tms {  
  5.     clock_t tms_utime;   /* user   time */  
  6.     clock_t tms_stime;   /* system time */  
  7.     clock_t tms_cutime;  /* user   time of children */  
  8.     clock_t tms_cstime;  /* system time of children */  
  9. };  
通过上面的介绍你会发现原来这个函数非常好用,只要在程序的末尾调用一下,就可以知道这个进程的system cpu time 和 user cpu time ,很方便吧,而返回值只要不等于(clock_t) -1,就说明返回成功。

[cpp]  view plain  copy
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<unistd.h>  
  4. #include<fcntl.h>  
  5. #include<string.h>  
  6. #include<errno.h>  
  7. #include<time.h>  
  8. #include<sys/times.h>  
  9. #include<sys/time.h>  
  10.   
  11. #define BUF_SIZE    512  
  12. #define FILE_NAME   "demo.txt"  
  13. #define err_exit(m) {perror(m); exit(1);}  
  14.       
  15. int main(){  
  16.     int i,fd,clocks_per_sec;    //文件句柄和每秒时钟数  
  17.     char    buf[BUF_SIZE];      //文件缓冲区大小  
  18.     struct  tms st_tms;     //times函数的机构  
  19.     clock_t start = clock();    //记录起始时间,  
  20.     fd = open(FILE_NAME, O_RDONLY | O_CREAT, 0664);  
  21.     if(fd == -1) err_exit("open error");  
  22.     while(read(fd, buf, BUF_SIZE) != 0);  
  23.     for(i = 0; i < 1000000000; i++);  
  24.     if (times(&st_tms) == -1) err_exit("times error");  
  25.     clock_t end = clock();  
  26.     clocks_per_sec = sysconf(_SC_CLK_TCK);  //用于获得times函数的单位时钟数  
  27.     printf("real  times: %7dus\n", (end-start)/CLOCKS_PER_SEC*1000000);  
  28.     printf("user  times: %7dus\n", st_tms.tms_utime*1000000/(clocks_per_sec));  
  29.     printf("syst  times: %7dus\n", st_tms.tms_stime*1000000/(clocks_per_sec));  
  30.     return 0;  
  31. }  
上面的代码需要注意以下两点:

1.为了demo.txt文件足够大,方便看出系统态下的执行时间,可以用下面的语句生成:

dd if=/dev/zero of=demo.txt bs=1M count=512 --可以生成512M的文件,很方便的!

2.times和clock都有clock_t类型的变量,将它们转化为秒要分别除以system(_SC_CLK_TCK)和宏CLOCKS_PER_SEC,它们的值是不同的,具体可以man一下这两个函数。


讲到这里就把struct tms 的最后两个成员变量也讲一下吧,tms_cutime和tms_cstime是用来记录子进程(们)的system cpu time 和 user cpu time。他们的值是在父进程中执行wait 或 waitpid 时开始记录,等到wait返回后才停止记录。看如下代码:

[cpp]  view plain  copy
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<unistd.h>  
  4. #include<fcntl.h>  
  5. #include<string.h>  
  6. #include<errno.h>  
  7. #include<time.h>  
  8. #include<sys/times.h>  
  9. #include<sys/time.h>  
  10.   
  11. #define BUF_SIZE    512  
  12. #define FILE_NAME   "demo.txt"  
  13. #define err_exit(m) {perror(m); exit(1);}  
  14.       
  15. int main(){  
  16.     int i,fd,clocks_per_sec;    //文件句柄和每秒时钟数  
  17.     char    buf[BUF_SIZE];      //文件缓冲区大小  
  18.     struct  tms st_tms;     //times函数的机构  
  19.     clock_t start = clock();    //记录起始时间,  
  20.     fd = open(FILE_NAME, O_RDONLY | O_CREAT, 0664);  
  21.     if(fd == -1) err_exit("open error");  
  22.     while(read(fd, buf, BUF_SIZE) != 0);  
  23.     for(i = 0; i < 1000000000; i++);  
  24.     /*  产生子进程,并完成与父进程同样的操作,最后查看相应的时间值 */  
  25.     int pid;  
  26.     if((pid = fork()) < 0){  
  27.         err_exit("fork error");  
  28.     }else if(pid == 0){  
  29.         int i = 0;   
  30.         for( ; i < 1000000000; i++);  
  31.         lseek(fd, 0, SEEK_SET); //重置读取位置,由于是复制父进程的,可能已到达文件末尾  
  32.         while(read(fd, buf, BUF_SIZE) > 0);  
  33.         exit(0);        //子进程退出  
  34.     }else{  
  35.         wait(-1);       //父进程等待子进程  
  36.     }  
  37.       
  38.     if (times(&st_tms) == -1) err_exit("times error");  
  39.     clock_t end = clock();  
  40.     clocks_per_sec = sysconf(_SC_CLK_TCK);  //用于获得times函数的单位时钟数  
  41.     printf("real  times: %7dus\n", (end-start)/CLOCKS_PER_SEC*1000000);  
  42.     printf("user  times: %7dus\n", st_tms.tms_utime*1000000/(clocks_per_sec));  
  43.     printf("syst  times: %7dus\n", st_tms.tms_stime*1000000/(clocks_per_sec));  
  44.     printf("child user times: %7dus\n", st_tms.tms_cutime*1000000/(clocks_per_sec));  
  45.     printf("child syst times: %7dus\n", st_tms.tms_cstime*1000000/(clocks_per_sec));  
  46.     return 0;  
  47. }  

注意:linux中clock函数并不能统计子进程(们)的时间哦,所以最后那个real time 只是父进程的时间,如果要统计可以使用time函数啦,time返回的时间点,所以当然足够精确啦!编译执行,看一下结果是否符合我们的预期值。


相关链接:https://stackoverflow.com/questions/17432502/how-can-i-measure-cpu-time-and-wall-clock-time-on-both-linux-windows#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值