Linux下程序时间消耗监控与统计

良好的计时器可帮助程序开发人员确定程序的性能瓶颈,或对不同算法进行性能比较。但要精确测量程序的运行时间并不容易,因为进程切换、中断、共享的多用户、网络流量、高速缓存访问及转移预测等因素都会对程序计时产生影响。

抛开这些影响因素,本文仅关注 Linux 系统中用户态程序执行时间的计算方式,即基于类 UNIX 系统的 time 命令统计一个程序或比较不同算法的时间消耗。

基本概念

1. 日历时间

Coordinated Universal Time(UTC)

世界协调时间(又称世界标准时间),旧称格林威治标准时间( Greenwich Mean Time, GMT )。

Calendar Time

日历时间,即从一个标准时间点到此时的时间所经过的秒数。该标准时间点因编译器而异,但对编译系统而言标准时间点不变。该编译系统中的时间对应的日历时间都通过该标准时间点衡量,故日历时间是“相对时间”。UNIX/Linux 的时间系统由 “新纪元时间( Epoch )” 开始算起,该起点指定为 1970 年 1 月 1 日凌晨 0 时 0 分 0 秒(格林威治时间)。Microsoft C/C++ 7.0 中标准时间点指定为 1899 年 12 月 31 日 0 时 0 分 0 秒,而其它版本的 Microsoft C/C++ 和所有不同版本的 Visual C++ 中标准时间点指定为 1970 年 1 月 1 日 0 时 0 分 0 秒。日历时间与时区无关。

Epoch

时间点。时间点在标准 C/C++ 中是一个整数( time_t ),它用此刻的时间和标准时间点相差的秒数(即日历时间)来表示。目前大部分 UNIX 系统采用 32 位记录时间,正值表示为 1970 年以后,负值则表示 1970 年以前。可简单地估算出所能表达的时间范围:1970±((231-1)/3600/24/365)≈[1901,2038] 年。为表示更久远的时间,某些编译器厂商引入 64 位甚至更长的整型数来保存日历时间。

2. 进程时间

进程时间也称 CPU 时间,用以度量进程使用的中央处理器资源。进程时间以时钟滴嗒计算,通常使用三个进程时间值,即实际时间(Real)、用户 CPU 时间(User)和系统 CPU 时间(Sys)。

实际时间指实际流逝的时间;用户时间和系统时间指特定进程使用的 CPU 时间。具体区别如下:

Real:是从进程开始执行到完成所经历的挂钟(wall clock)时间,包括其他进程使用的时间片(time slice)和本进程耗费在阻塞(如等待 I/O 操作完成)上的时间。该时间对应秒表(stopwatch)直接测量。

User:是进程执行用户态代码(内核外)耗费的 CPU 时间,仅统计该进程执行时实际使用的 CPU 时间,而不计入其他进程使用的时间片和本进程阻塞的时间。

Sys:是该进程在内核态运行所耗费的 CPU 时间,即内核执行系统调用所使用的 CPU 时间。

CPU 总时间(User+Sys)是 CPU 执行用户进程操作和内核(代表用户进程执行)系统调用所耗时间的总和,即该进程(包括其线程和子进程)所使用的实际 CPU 时间。若程序循环遍历数组,则增加用户 CPU 时间;若程序执行 exec 或 fork 等系统调用,则增加系统 CPU 时间。

在多核处理器机器上,若进程含有多个线程或通过 fork 调用创建子进程,则实际时间可能小于 CPU 总时间——因为不同线程或进程可并行执行,但其时间会计入主进程的 CPU 总时间。若程序在某段时间处于等待状态而并未执行,则实际时间可能大于 CPU 总时间。其数值关系总结如下:

Real

Real ≈ CPU,表明进程为计算密集型(CPU bound),未并行执行。

Real > CPU,表明进程为 I/O 密集型(I/O bound),多核并行执行优势并不明显。

在单核处理器上,Real 时间和 CPU 时间之差,即Real- (User+Sys)是所有延迟程序执行的因素的总和。可估算程序运行期间的 CPU 利用率为CpuUsage = (User + Sys) / Real * 100(%)

在 SMP(对称多处理系统)上,该差值近似为Real* ProcessorNum - (User + Sys)。这些因素包括:

调入程序文本和数据的 I/O 操作。

获取程序实际使用内存的 I/O 操作。

由其它程序消耗的 CPU 用时。

由操作系统消耗的 CPU 用时。

3. LInux命令

在 Linux 下,命令有几种类型,包括:

可以通过 $PATH 来找到的程序可执行文件,即文件系统中的命令;

通过 shell 内置命令 alias 创建的 Linux 别名,即用户定义的命令;

shell 程序设计中的保留字,即 shell keyword,如 if、then、fi、for、while、case、esac、else、until 等;

在 shell 脚本中写的 shell 函数;

shell 中内置的 Linux 命令,如 pwd、cd、bg、alias、history、type、source、read、exit 等,我们可以通过 Linux 内置的 type 命令来列出或检查 Linux 内置命令。

【左右滑动查看完整信息】

命令详解

当测试一个程序或比较不同算法时,执行时间是非常重要的,一个好的算法应该是用时最短的。所有类UNIX系统都包含 time(shell keyword),使用这个命令可以统计时间消耗。我们常用的 time 其实是一个 Shell 关键字,还有一个外部命令 /usr/bin/time,两者最主要的区别在于外部命令 /usr/bin/time 功能更强大。

【左右滑动查看完整信息】

/usr/bin/time 功能非常强大,我们可以使用 -v 参数查看打印出来比较详细的信息:

【左右滑动查看完整信息】

外部命令 /usr/bin/time 一些常用参数:

使用-o选项将执行时间写入到文件中

【左右滑动查看完整信息】

使用-a选项追加信息

【左右滑动查看完整信息】

使用-f选项格式化时间输出

【左右滑动查看完整信息】

-f选项后的参数:

【左右滑动查看完整信息】

实际操作

对 echo、gzip、自己编写的 python 程序,使用 time 对时间消耗进行统计:

【左右滑动查看完整信息】

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180707G1LZNY00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券