在 Linux 如何优雅的统计程序运行时间?恕我直言,你运行的可能是假 time
最近在使用 time 命令时,无意间发现了一些隐藏的小秘密和强大功能,今天分享给大家。
time 在 Linux 下是比较常用的命令,可以帮助我们方便的计算程序的运行时间,对比采用不同方案时程序的运行性能。看似简单的命令,其实蕴藏着很多细节和技巧,来跟着肖邦一起学习吧。
1 基础用法详解
先来看下最基础的用法,也可能是大家最常见的用法了
root@chopin:~$ time find . -name "chopin.txt"
......
real 0m0.174s
user 0m0.084s
sys 0m0.084s
可以很清楚看到,find 命令执行的时间为 0.174s,是不是很简单,很方便呢
不过,time 命令输出了三个参数,我们只用到了第一个参数,其它两个参数代表什么含义呢?
这里我来解释一下:
real:表示的是墙上时间,说白了,其实就是从程序运行开始到结束所经历的时间; user:表示程序运行期间,cpu 在用户态所花费的时间; sys:表示程序运行期间,cpu 在内核态所花费的时间;
细心的读者会发现,上述案例中的 user + sys 不等于 real,这是怎么回事呢?
其实上边解释的 user 和 sys,是 cpu 执行指令所消耗的时间,并不包含:进程阻塞 IO、调度排队,这些非 cpu 运行时间。
案例中 find 执行查找文件过程中,会有磁盘 IO 读取,这时 cpu 会被释放出来干别的事情,这些 IO 消耗的时间,是不包含在 user 和 sys 统计数据中,所以就出现了 real 时间大于 user + sys 了。
再通过一个示例来验证并加强我们的理解
root@chopin:~$ time sleep 2
real 0m2.001s
user 0m0.000s
sys 0m0.000s
可以清楚地看到,sleep 命令基本上没有消耗 cpu,程序真实的运行时间就是 2 秒
那我们是不是可以得出如下结论了呢:
real >= user + sys
其实这个结论在单个 cpu 情况下,是正确的。
如果服务器是多个 cpu,你的程序正好可以将多个 cpu 充分利用起来,程序运行期间是多核心并行的,那么 user + sys 统计的 cpu 时间可能就会大于 real 时间啦
所以这 3 个时间之间的关系并不是恒定的,你需要清楚的了解服务器是否为多个核心。
其实,通过统计到的 cpu 消耗时间,我们也可以大概知道,程序运行期间 cpu 利用情况。对于单核,计算密集型的程序,real 会很接近 user 和 sys 时间之和的。
Tips:有些同学可能对操作系统可能不太熟悉,这里简单科普下内核态和用户态的基本概念
Linux 为使系统更稳定,采取了隔离保护的措施,运行状态分为内核态和用户态:
用户态:用户代码不具备直接访问底层资源的能力,需要借助内核提供的系统调用 API。在这种隔离保护下,即使用户程序崩溃,也不会影响整个系统的功能。 内核态:内核代码具备最大权限,可执行任意 cpu 指令,不受任何限制。内核态通常是操作系统提供的最底层、最可靠的代码运行的,内核态的代码崩溃是灾难性的,影响整个系统的正常运行。
2 你运行的可能是假time
time 还有其它功能吗?看一下帮助文档吧
root@chopin:~$ time --help
--help: command not found
real 0m0.129s
user 0m0.084s
sys 0m0.036s
竟然报错,将 --help 当成了命令来执行了,难道 time 就这么点能耐吗?
好吧,我也不卖关子了,直接说答案:你运行的可能是假time。你可能有点懵逼,怎么就假的了。
其实在 Linux 系统上,使用 time 时,你可能会遇到三种版本:
# 1. Bash
time is a shell keyword
# 2. Zsh
time is a reserved word
# 3. GNU time
time is /usr/bin/time
我们当前 Shell 是 Bash,可以通过 type 命令
root@chopin:~$ type time
time is a shell keyword
可以看到,我们刚才执行的 time 是 Shell 的内置命令,如果你用的是 zsh,默认使用的 time 也是对应内置命令。
GNU time 命令路径是 /usr/bin/time,一般的 Linux 发行版都带有这个命令,它才是我们今天的猪脚。
3 更强大的功能
GNU time 命令提供了更强大的功能:
更详细的统计信息 更丰富的格式输出 支持保存统计数据到文件
下边我们来学习写 GNU time 的使用
1. 最简单的用法
root@chopin:~$ /usr/bin/time sleep 2
0.00user 0.00system 0:02.00elapsed 0%CPU (0avgtext+0avgdata 1784maxresident)k
0inputs+0outputs (0major+72minor)pagefaults 0swaps
使用 GNU time 命令,直接使用绝对路径即可,我们可以看到输出信息更多了,不过格式有点丑,后边会讲如何自定义格式。
2. 保持内置 time 的输出样式
有同学会问,能输出内置 Shell 那种的格式么?可以的,使用 -p 选项即可
root@chopin:~$ /usr/bin/time -p sleep 2
real 2.00
user 0.00
sys 0.00
3. 输出更详细的信息
还可以输出更加详细的信息,让你对程序运行信息一目了然。请使用 -v 选项
root@chopin:~$ /usr/bin/time -v sleep 2
Command being timed: "sleep 2"
User time (seconds): 0.00
System time (seconds): 0.00
Percent of CPU this job got: 0%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.00
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 1804
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 71
Voluntary context switches: 1
Involuntary context switches: 1
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
这里详细介绍下 time 命令输出各项指标
(一)时间相关

(二)内存相关

(三)IO 相关

4. 统计信息输出到文件
如果你希望将 time 统计的信息输出到文件,可以使用 -o 选项
root@chopin:~$ /usr/bin/time -v -o a.txt sleep 2
统计信息直接保存到了 a.txt,如果你希望统计信息能够追加到文件,可以额外加 -a 选项
5. 自定义格式输出
如果命令中内置的输出格式,不符合你的需求,GNU time 可以支持自定义输出格式,通过选项 -f 可以各种指标参数
/usr/bin/time -f "real %e\nuser %U\nsys %S\n" sleep 1
real 1.00
user 0.00
sys 0.00
具体支持的格式,贴心的肖邦已经帮你整理好了

这些格式参数太多了,平时大部分情况用不到,可以收藏起来,以便后期使用时可以快速参考。
4 性能分析中的作用
看到这么多系统参数指标,难免会有同学会感到疑惑,这些参数能干什么呀?
其实这些指标,对应到操作系统 cpu、内存、IO 这几方面。深刻的理解了这些指标参数,可以帮助你从本质上把握程序的运行情况,甚至可以协助你分析程序的性能瓶颈。
下边我简单解释几个概念,希望能起到抛砖引玉的作用。
(一)CPU 时间
cpu 时间包括:real、user、sys,当 user + sys >= real 时,说明该程序是计算密集型;当 user + sys 远小于 real 时,说明存在较多的 IO 等待。
(二)上下文切换
平时所说的上下文,是指进程的运行环境,包括当时的寄存器值、内存堆栈等信息,内核根据上下文完全恢复一个被打断的进程任务。
当执行系统调用、进程切换时,都会产生上下文切换。切换上下文时,操作系统需要为进程保存和恢复上下文信息。
上下文切换分为主动和被动两种,主动上下文切换多,说明存在较多的阻塞调用;被动上下文切换说明 cpu 使用率高。
当上下文切换过多时,意味着较多的 cpu 时间花费在上下文切换上,导致 cpu 处理进程任务的有效时间大大减少。
(三)缺页异常
次缺页异常较多,说明程序的内存布局相对合理,命中率高;当主缺页异常较多时,说明程序对内存的访问跳跃性大,命中率低。
处理缺页异常和切换上下文的时间,不包含在 user 和 sys 中,当发现 user + sys 远小于 real 时,则很可能大部分时间都消耗在这些地方,需要重点分析这两点。
推荐阅读
推荐阅读:
写给 Linux 初学者的一封信 全网最详尽的负载均衡原理图解 上古神器 sed 教程详解,小白也能看的懂 Linux 三剑客之 grep 教程详解 Linux 文件搜索神器 find 实战详解,建议收藏! Linux 网络分析必备技能:tcpdump 实战详解 Linux 三剑客之 awk 实战详解教程 80% 的人都不会的 15 个 Linux 实用技巧 谁动了我的Linux?原来history这么强大! 在Linux上使用time优雅的统计程序运行时间
欢迎各位老铁关注

在 Linux 如何优雅的统计程序运行时间?恕我直言,你运行的可能是假 time的更多相关文章
- Java统计程序运行时间
代码如下: 第一种是以毫秒为单位计算的. long startTime = System.currentTimeMillis(); //获取开始时间 doSomething(); //测试 ...
- linux 统计 程序 运行时间
测试 代码运行时间 linux 中的 <sys/time.h> 中 有个函数可以获取当前时间,精确到 微秒 ----> gettimeofday() #include <sy ...
- C++统计程序运行时间代码片段
因为经常需要统计代码的运行时间,所以计时功能就显得很重要, 记录一下现在喜欢用的计时方式,供日后查阅. 1.下面是计时主函数, bool TimeStaticMine(int id,const cha ...
- Spark中统计程序运行时间
import java.text.SimpleDateFormat import java.util.Date val s=NowDate() //显示当前的具体时间 val now=new Date ...
- ARTS-S c语言统计程序运行时间
#include <stdio.h> #include <sys/time.h> #include <unistd.h> int main() { struct t ...
- VC中监测程序运行时间(二)-毫秒级
/* * 微秒级计时器,用来统计程序运行时间 * http://blog.csdn.net/hoya5121/article/details/3778487#comments * //整理 [10/1 ...
- linux下统计程序/函数运行时间(转)
一. 使用time 命令 例如编译一个hello.c文件 #gcc hello.c -o hello 生成了hello可执行文件,此时统计该程序的运行时间便可以使用如下命令 #time ./hello ...
- java统计程序运行的时间
耗时统计 第一种是以毫秒为单位计算的.long startTime = System.currentTimeMillis(); //获取开始时间 //程序做一些功能性的操作doSomething ...
- C#测量程序运行时间及cpu使用时间
转载:http://www.cnblogs.com/yanpeng/archive/2008/10/15/1943369.html 对一个服务器程序想统计每秒可以处理多少数据包,要如何做?答案是用处理 ...
随机推荐
- Nuxt.js vue服务端渲染
一.为什么要用Nuxt.js 原因其实不用多说,就是利用Nuxt.js的服务端渲染能力来解决Vue项目的SEO问题. 二.Nuxt.js和纯Vue项目的简单对比 1. build后目标产物不同 vue ...
- 2018ICPC南京D. Country Meow
题目: 题意:三维里有n个点,找一个最小的球将所有点覆盖. 题解:退火法模拟的一道板子题. 1 #include <stdio.h> 2 #include <iostream> ...
- Cookie与Session的安全性
说到cookie与session我们首先要说一下为什么要引入这两个东西,这两个多西到底是干什么的 起源 由于HTTP协议使无状态的: 每一次请求都是新的请求,不会记得之前通信的状态 客户端与服务端的一 ...
- 前端知识-CS-01
一.选择器 通过什么方式来定位 1.sytle标签 style标签功能:写css样式的sytle标签的几种写法:1.可以在head里面添加一个style标签 2.在head标签中 通过link标签,引 ...
- java中ReentrantLock核心源码详解
ReentrantLock简介 ReentrantLock是一个可重入且独占式的锁,它具有与使用synchronized监视器锁相同的基本行为和语义,但与synchronized关键字相比,它更灵活. ...
- springBoot高级:自动配置分析,事件监听,启动流程分析,监控,部署
知识点梳理 课堂讲义 02-SpringBoot自动配置-@Conditional使用 Condition是Spring4.0后引入的条件化配置接口,通过实现Condition接口可以完成有条件的加载 ...
- 推荐模型NeuralCF:原理介绍与TensorFlow2.0实现
1. 简介 NCF是协同过滤在神经网络上的实现--神经网络协同过滤.由新加坡国立大学与2017年提出. 我们知道,在协同过滤的基础上发展来的矩阵分解取得了巨大的成就,但是矩阵分解得到低维隐向量求内积是 ...
- 最小生成树(Prim算法,Kruskal算法 )
声明:图片及内容基于https://www.bilibili.com/video/BV1yp4y1Q74o?from=articleDetail 最小生成树原理 . 普利姆(Prim)算法 原理 Pr ...
- .NET 开源配置组件 AgileConfig 初体验
介绍 在微服务大行其道的今天,系统会被拆分成多个模块,作为单独的服务运行,同时为了集中化管理,我们还需要日志中心,配置中心等,很多开发人员可能更熟悉 ApolloConfig,这个组件功能也很完善,d ...
- Nginx错误日志(error_log)配置及信息详解
Nginx错误日志信息介绍 Nginx的错误信息是调试Nginx服务的重要手段,属于核心功能模块(ngx_core_module)的参数,该参数的名字为error_log,可以放在Main区块中全局配 ...