文章结构:

CPU时间(CPU TIME)是指当应用进程启动后,占用CPU进行计算所进行的时间绝对值,或叫时间点。如果进程进入中断、挂起、休眠等行为时,是不占用CPU的,所以CPU时间并不会跟着增加,且进程恢复运行后所获得的CPU时间值与运行中断之前的时间值是连续的,并不会因为运行的暂停而导致CPU时间的跳跃。这是和普通的日常时间值不一样的点。另一个不同的点是CPU时间并不是以秒为单位的,而是处理器的时钟周期为单位。

获取CPU时间的函数

#include

clock_t clock(void)

该函数返回CPU时间,CPU时间并不一定会从0开始,所以要计算进程的一段代码所消耗的CPU时间记录需要在代码前后获取各自的起始和终止CPU时间,两者之差即为所消耗的CPU时间,即为处理器耗时(Processor Time)。

要将clock_t转换为秒数,需要除以宏CLOCKS_PER_SEC生成的值,即为秒数。但要注意的是由于在不同的系统中clock_t或CLOCKS_PER_SEC可能为int也可能为浮点型数值,所以在计算时需要在计算过程中并其强制转换为double以保证计算结果。

另外需要注意的是clock()函数所返回的值在32位系统上每72分钟就会恢复原始值一次。

clock()如果执行错误,则会返回-1。

获取CPU时间与更详细的进程时间还有另外一个函数:

#include

clock_t times(struct tms *buf);

struct tms {

clock_t tms_utime; /* user time */

clock_t tms_stime; /* system time */

clock_t tms_cutime; /* user time of children */

clock_t tms_cstime; /* system time of children */

};

函数times()会将进程的处理器时间分类。在参数tms中各字段含义为:

tms_utime:用户层处理器耗时。即执行该进程的实现代码所消耗的CPU时间和。

tms_stime:系统层处理器耗时。即该进程实现的代码调用了系统内核代码,由这部分内核代码执行所消耗的CPU时间和。

tms_cutime:子进程用户层处理器耗时。即如果当前进程通过调用system()或fork()函数导致产生新的子进程(数量前后可能为多个),则记录所有子进程的实现代码所消耗的CPU时间和。

tms_cstime:子进程用户层处理器耗时。即如果当前进程通过调用system()或fork()函数导致产生新的子进程(数量前后可能为多个),则记录所有子进程实现的代码调用了系统内核代码,由这部分内核代码执行所消耗的CPU时间和。

函数times()所返回的值单位都是时钟滴哒(clock tick)数。要获取每秒钟的时钟滴哒可以调用函数sysconf(_SC_CLK_TCK);来获取。为了保证精度,在计算耗时时,也要在计算过程中将参与的计算值转换为double以保证计算结果。

函数times()所返回的值表示过去某个时间点到函数调用此刻的时间消耗长度。所以进程的中断、挂起、休眠等行为仍会导致返回值的持续增加。这一点是与clock()的不同所在。通常也利用这个特点来计算进程的前后自然时间耗时时长。

在计算时长方面,times()通过精确到秒以下(可能是毫秒,因为是double类型的计算),但缺点是参数buf必须不为空;difftime()由于其参数设定的原因只能精确到秒,能力是最弱的;gettimeofday()所获取的timeval则可精确到微秒,只是计算时间差值时麻烦一点。

除了在代码中调用函数来计算各种耗时以外,还可能通过命令time来显示耗时统计。

Time命令原型如下:

time [options] command [arguments...]

options:time命令的可选参数,只接受-p,表示为按标准格式输出。如下:

real: 命令`date`的全部运行时间时长。

user: 命令`date`(包括其子进程,如果有的话)的用户层处理器耗时。

sys : 命令`date`(包括其子进程,如果有的话)的系统层处理器耗时。

command:time要统计的命令。

[arguments]:command命令所接受的参数。

命令Time的输出是可以自定义的,通过设置环境变量TIMEFORMAT指定输出所要的格式化结果。

另从man手册中查看Time还具有查看CPU占用率、I/O数据量等功能(可是按文档在Mac上来操作没有成功呀…)

接下来的代码将演示:

#include #include #include

pid_t getpid(void); // 获取进程id

pid_t getppid(void); // 获取父进程id

pid_t gettid(void){ // 获取线程id

return syscall(SYS_gettid);

}

这里值得提一下的是getttid()是系统内核非对外公开的函数。所以这里根据其源码实现利用syscall()方法来获取线程id。

#include

unsigned int sleep(unsigned int seconds);

参数seconds表示线程的休眠时间,单位为秒。在指定的休眠时间内,线程会暂停工作直至时间到期或被中断。

为了测试times()中的tms_cutime和tms_cstime,需要创建一个子进程,这里用到system()函数。

#include

int system(const char *command);

参数command为命令,可以是可执行程序路径也可以是系统支持的命令。system()函数会调用fork()去创建一个子进程并执行参数command。在子进程执行期间,父进程所调用的线程是被中断的,不会再进行任何操作直至等到子进程全部执行完毕。子进程所产生的日志输出也将在结束之后才会被打印出来。

示例代码中,通过在程序的开头、进行中、结束各个阶段执行clock()来获取进程当前的CPU时间点,通过减法操作最终得到每个阶段的处理器耗时。

执行完sleep()的前后CPU时间对比可以验证CPU时间是进程所消耗处理器而产生的连续的时间集合。CPU用了多少就是多少,而与正常的时间流逝无关。

执行完system()的前后CPU时间对比可以验证子进程的CPU时间并不会被计算在父进程中,可以通过times()区分。

clock_t c_start = clock();

sleep(2); // 进程进入休眠

clock_t c_mid01 = clock();

doCopyFile(); // 进程进入繁忙的工作状态

clock_t c_mid02 = clock();

system(“”); // 生成子进程

clock_t c_end = clock();

doCopyFile()函数是复制文件的代码实现,本示例中所复制的文件大小为35M,耗时大概3.5s左右。

具体复制代码实现可以查看之前的文章:【C/C++】文件创建、打开、读、写、复制、关闭、删除等操作汇总

获取耗时详情的前提是要获取每秒时钟滴哒数;而详情则是通过struct tms的前后对比得出的时间差:

// process_start与后面的process_end用于计算整个进程的耗时

clock_t process_start = times(&sys_t_start);

// 获取每秒的时钟滴哒数

long tck = sysconf(_SC_CLK_TCK);

... ... ...

struct tms sys_t_end;

clock_t process_end = times(&sys_t_end);

printf("4. sys time: user time=%f, stime=%f, cutime=%f, cstime=%f \n",

(sys_t_end.tms_utime - sys_t_start.tms_utime)/(double)tck,

(sys_t_end.tms_stime - sys_t_start.tms_stime)/(double)tck,

(sys_t_end.tms_cutime - sys_t_start.tms_cutime)/(double)tck,

(sys_t_end.tms_cstime - sys_t_start.tms_cstime)/(double)tck);

printf("5. real elapsed time=%f \n", ((process_end - process_start)/(double)tck));

最后看代码的运行结果吧,如下图:

图中,real elapsed time=9.250000与time命令所打印出来的real 0m9.249s相符;

user time=3.360000 , cutime=3.380000两者之和与user 0m6.757s相符;

stime=0.120000 cstime=0.120000两者之和与sys 0m255s相符。

数值上不是绝对相等,代码内的自我计算总是会少于time的值,因为代码内是计算完了之后要打印的,这部分打印及退出的时间是代码的盲区,而time命令能统计到。

以下为实现代码:

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

49

50

51

52

53

54

55

56

57#include

#include

#include

#include

#include

#include

#include

#include

#include

pid_t gettid(void){

return syscall(SYS_gettid);

}

int main(int argc, char **argv) {

// author : sodino@qq.com

struct tms sys_t_start;

clock_t process_start = times(&sys_t_start);

clock_t c_start = clock();

times(&sys_t_start);

printf(" pid=%d ppid=%d tid=%d \n", getpid(), getppid(), gettid());

long tck = sysconf(_SC_CLK_TCK);

sleep(2);

clock_t c_mid01 = clock();

double diff = (c_mid01 - c_start)/(double)CLOCKS_PER_SEC;

printf("1. after sleep(2) consume clock time=%f \n", diff);

doCopyFile();

clock_t c_mid02 = clock();

diff = (double)(c_mid02 - c_start)/CLOCKS_PER_SEC;

printf("2. after doCopyFile() consume clock time=%f \n", diff);

// 这里会产生新的进程

system("/Users/sodino/workspace/xcode/Define/Define/t_copy.out");

clock_t c_end = clock();

diff = (double)(c_end - c_start)/CLOCKS_PER_SEC;

printf("3. after system() consume clock time=%f \n", diff);

struct tms sys_t_end;

clock_t process_end = times(&sys_t_end);

printf("4. sys time: user time=%f, stime=%f, cutime=%f, cstime=%f \n",

(sys_t_end.tms_utime - sys_t_start.tms_utime)/(double)tck,

(sys_t_end.tms_stime - sys_t_start.tms_stime)/(double)tck,

(sys_t_end.tms_cutime - sys_t_start.tms_cutime)/(double)tck,

(sys_t_end.tms_cstime - sys_t_start.tms_cstime)/(double)tck);

printf("5. real elapsed time=%f \n", ((process_end - process_start)/(double)tck));

return EXIT_SUCCESS;

}

linux查看程序中最耗时的代码,【Linux】CPU时间与处理器耗时相关推荐

  1. linux cpu 时间,【Linux】CPU时间与处理器耗时

    文章结构: CPU时间(CPU TIME)是指当应用进程启动后,占用CPU进行计算所进行的时间绝对值,或叫时间点.如果进程进入中断.挂起.休眠等行为时,是不占用CPU的,所以CPU时间并不会跟着增加, ...

  2. Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序

    文章目录: 1 linux查看那端口监听情况 2 Linux查看某个端口对应的进程号和程序 1 linux查看那端口监听情况 linux中可以使用netstat命令查看端口监听情况,首先来看一下该命令 ...

  3. DW写的页面,在浏览者查看器中出现大量其他代码

    DW写的页面,图1在浏览者查看器中出现大量其他代码与自己编写的H5中<body>的不一样,是因为浏览器用了油猴插件还是因为其他原因  图二是预想中的情况

  4. linux 查看当前用户和组的信息,Linux查看所有用户和组信息

    主要通过以下两个命令: cat /etc/passwd cat /etc/group 步骤一:cat /etc/passwd查看所有的用户信息,详情如下图: 步骤2:cat /etc/passwd|g ...

  5. linux查看进程中的线程名,linux 怎么样查看一个进程的线程

    一.linux系统支持的最大进程数 限制1:既然系统使用pid_t表示进程号,那么最大进程数不能超过pid_t类型的最大值吧 限制2:使用命令ulimit -u查看系统中限制的最大进程数,我的机器上是 ...

  6. linux 查看工程用什么工具,工程师工具包-Linux常用命令及常用操作-持续更新中...

    Linux系统命令相关 系统相关 date date 查看系统时间 $date 2017年 09月 18日 星期一 18:01:06 CST date -R查看系统时间,并且在时间后面加上时区的显示 ...

  7. linux下怎么查看程序异常,如何检测、定位linux程序异常

    作为linux开发,在工作中或者面试的时候经常会遇到怎么检测程序异常的问题,下面对此作一个总结. 0. 查看程序日志.项目更新日志,发现可疑的地方 使用linux查看内存cpu指令,top.ps初步看 ...

  8. linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间

    1 linux上根据运行程序的进程号,查看程序所在的绝对路径 1.如下,我想查看python 25_run_train_tripletloss_sknet_8w_offline_c_plus.py 这 ...

  9. linux c程序中获取shell脚本输出

    http://doc.chinaunix.net/linux/201004/512284.shtml1. 前言 Unix界有一句名言:"一行shell脚本胜过万行C程序",虽然这句 ...

最新文章

  1. Android Volley 库通过网络获取 JSON 数据
  2. mac 用 brew
  3. POJ1284:Primitive Roots——题解
  4. anaconda 安装 pytorch
  5. Android之build.gradle配置签名
  6. 数组转List的3种方法和使用对比!
  7. 《我也能做CTO之程序员职业规划》和《.NET软件设计新思维——像搭积木一样搭建软件》新书发布会 回顾
  8. 在Docker上运行Asp.Net Core示例网站
  9. DirectX修复工具
  10. java利用反射映射两个不同对象的属性值
  11. ORBSLAM3整体框架
  12. FreeRTOS历史版本更新记录
  13. CH0502 七夕祭
  14. python有趣小程序 表白-python表白小程序
  15. html如何给盒子设置位置,CSS盒子定位
  16. 小试牛刀 - WordCount
  17. uni-app 学习笔记
  18. 计算机专业省赛一等奖有什么好处,竞赛省一等奖有什么用
  19. MS11-030-DNS 解析漏洞复现
  20. 基于jsp,ssm进销存管理系统

热门文章

  1. MongoDB和Elasticsearch的各使用场景对比
  2. Jmeter之JDBC Request与mysql
  3. 如何爬取了知乎用户信息,并做了简单的分析
  4. QT学习-核心类列表-4、Qt WebKit Widgets 5、Qt3DCore
  5. Python 学习第十七天 jQuery
  6. 在虚拟机中安装红旗桌面7.0 Linux操作系统的详细图文教程
  7. SQL SERVER事务处理
  8. Swing透明和变换
  9. JZOJ 1035. 【SCOI2009】粉刷匠
  10. 第十四章 七段数码管绘制时间