linux查看程序中最耗时的代码,【Linux】CPU时间与处理器耗时
文章结构:
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时间与处理器耗时相关推荐
- linux cpu 时间,【Linux】CPU时间与处理器耗时
文章结构: CPU时间(CPU TIME)是指当应用进程启动后,占用CPU进行计算所进行的时间绝对值,或叫时间点.如果进程进入中断.挂起.休眠等行为时,是不占用CPU的,所以CPU时间并不会跟着增加, ...
- Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
文章目录: 1 linux查看那端口监听情况 2 Linux查看某个端口对应的进程号和程序 1 linux查看那端口监听情况 linux中可以使用netstat命令查看端口监听情况,首先来看一下该命令 ...
- DW写的页面,在浏览者查看器中出现大量其他代码
DW写的页面,图1在浏览者查看器中出现大量其他代码与自己编写的H5中<body>的不一样,是因为浏览器用了油猴插件还是因为其他原因 图二是预想中的情况
- linux 查看当前用户和组的信息,Linux查看所有用户和组信息
主要通过以下两个命令: cat /etc/passwd cat /etc/group 步骤一:cat /etc/passwd查看所有的用户信息,详情如下图: 步骤2:cat /etc/passwd|g ...
- linux查看进程中的线程名,linux 怎么样查看一个进程的线程
一.linux系统支持的最大进程数 限制1:既然系统使用pid_t表示进程号,那么最大进程数不能超过pid_t类型的最大值吧 限制2:使用命令ulimit -u查看系统中限制的最大进程数,我的机器上是 ...
- linux 查看工程用什么工具,工程师工具包-Linux常用命令及常用操作-持续更新中...
Linux系统命令相关 系统相关 date date 查看系统时间 $date 2017年 09月 18日 星期一 18:01:06 CST date -R查看系统时间,并且在时间后面加上时区的显示 ...
- linux下怎么查看程序异常,如何检测、定位linux程序异常
作为linux开发,在工作中或者面试的时候经常会遇到怎么检测程序异常的问题,下面对此作一个总结. 0. 查看程序日志.项目更新日志,发现可疑的地方 使用linux查看内存cpu指令,top.ps初步看 ...
- linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
1 linux上根据运行程序的进程号,查看程序所在的绝对路径 1.如下,我想查看python 25_run_train_tripletloss_sknet_8w_offline_c_plus.py 这 ...
- linux c程序中获取shell脚本输出
http://doc.chinaunix.net/linux/201004/512284.shtml1. 前言 Unix界有一句名言:"一行shell脚本胜过万行C程序",虽然这句 ...
最新文章
- Android Volley 库通过网络获取 JSON 数据
- mac 用 brew
- POJ1284:Primitive Roots——题解
- anaconda 安装 pytorch
- Android之build.gradle配置签名
- 数组转List的3种方法和使用对比!
- 《我也能做CTO之程序员职业规划》和《.NET软件设计新思维——像搭积木一样搭建软件》新书发布会 回顾
- 在Docker上运行Asp.Net Core示例网站
- DirectX修复工具
- java利用反射映射两个不同对象的属性值
- ORBSLAM3整体框架
- FreeRTOS历史版本更新记录
- CH0502 七夕祭
- python有趣小程序 表白-python表白小程序
- html如何给盒子设置位置,CSS盒子定位
- 小试牛刀 - WordCount
- uni-app 学习笔记
- 计算机专业省赛一等奖有什么好处,竞赛省一等奖有什么用
- MS11-030-DNS 解析漏洞复现
- 基于jsp,ssm进销存管理系统