8.3 计算命令执行时间

当测试一个应用程序或比较不同的算法时,程序的执行时间非常重要。一个好算法的执行时间应该最短。在某些情况下,我们需要监视程序执行所需要的时间。例如,当学习排序算法时,你该怎么样表明哪一种算法更快一些?答案就是计算这些算法针对同一个数据集所耗费的时间。让我们看看如何计算。

实战演练

所有的类UNIX操作系统都包含time命令。你可以将time放在需要计算执行时间的命令之前,例如:

  1. $ time COMMAND

命令COMMAND会执行并生成输出 。除此之外,time命令会将命令的执行时间添加到stderr中。例如:

  1. $ time ls
  2. test.txt
  3. next.txt
  4. real 0m0.008s
  5. user 0m0.001s
  6. sys 0m0.003s

输出中分别显示了执行该命令所花费的real时间、user时间以及sys时间。

  • real时间指的是挂钟时间(wall clock time),也就是命令从开始执行到结束的时间。这段时间包括其他进程所占用的时间片(time slice)以及进程被阻塞时所花费的时间(例如,为等待I/O操作完成所用的时间)。

  • user时间是指进程花费在用户模式(user-mode)中的CPU时间。这是唯一真正用于执行进程所花费的时间。执行其他进程以及花费在阻塞状态中的时间并没有计算在内。

  • sys时间是指进程花费在内核模式(in the kernel)中的CPU时间。它代表在内核中执行系统调用所使用的时间,这和库代码(library code)不同,后者仍旧运行在用户空间(user space)。与“user时间”类似,这也是真正由进程使用的CPU时间。

8.3 计算命令执行时间 - 图1 time命令的可执行二进制文件位于/usr/bin/time,还有一个Shell内建命令也叫做time。当运行time时,默认调用的是Shell的内建命令。Shell内建的time命令选项有限。因此,如果我们需要使用另外的功能,就应该使用可执行文件time的绝对路径(/usr/bin/time)。

可以用选项-o filename将命令执行时间写入文件:

  1. $ /usr/bin/time -o output.txt COMMAND

文件名应该出现在选项-o之后。

要将命令执行时间添加到文件而不影响其原有内容,使用选项-a以及-o

  1. $ /usr/bin/time -a -o output.txt COMMAND

我们也可以使用选项-f,利用格式字符串格式化时间输出。格式字符串由对应于特定选项的参数组成,这些参数以 % 作为前缀。real时间、user 时间、sys 时间的格式字符串分别如下:

  • real -%e

  • user -%U

  • sys -%S

通过结合参数字符串,我们就可以创建格式化输出:

  1. $ /usr/bin/time -f "FORMAT STRING" COMMAND

例如:

  1. $ /usr/bin/time -f "Time: %U" -a -o timing.log uname
  2. Linux

其中,%Uuser时间的参数。

格式化输出生成后被写入标准输出,执行时间信息被写入标准错误。我们可以用重定向操作符(>)对格式化输出重定向,用错误重定向操作符(2>)对时间信息重定向。例如:

  1. $ /usr/bin/time -f "Time: %U" uname> command_output.txt 2>time.log
  2. $ cat time.log
  3. Time: 0.00
  4. $ cat command_output.txt
  5. Linux

通过time命令可以获得进程的很多细节信息,包括退出状态、接收到的信号数量、进程上下文的切换次数等。每一个参数都可以用适合的格式字符串显示。

表8-1展示了一些可以使用的参数。

表 8-1

参  数 描  述
%C 进行计时的命令名称以及命令行参数
%D 进程非共享数据区域的大小,以KB为单位
%E 进程使用的real时间(挂钟时间),显示格式为[小时:]分钟:秒
%x 命令的退出状态
%k 进程接收到的信号数量
%W 进程被交换出主存的次数
%Z 系统的页面大小。这是一个系统常量,但在不同的系统中,这个常量值也不同
%P 进程所获得的CPU时间百分比。这个值等于user+system时间除以总共的运行时间。结果以百分比形式显示
%K 进程的平均总(data+stack+text)内存使用量,以KB为单位
%w 进程主动(voluntarily)进行上下文切换的次数,例如等待I/O操作完成
%c 进程被迫(involuntarily)进行上下文切换的次数(由于时间片到期)

例如,用参数 %Z显示系统页面大小:

  1. $ /usr/bin/time -f "Page size: %Z bytes" ls> /dev/null
  2. Page size: 4096 bytes

这里并不需要被计时命令的输出(即ls),因此为了使其不显示在终端中,我们将标准输出重定向到了/dev/null设备。

还有很多可用格式字符串,请阅读man time,以便获取更多的细节信息。