UNIX中的`time`命令对于基准测试是否足够准确?

51

假设我想要对两个程序进行基准测试:foo.py 和 bar.py。

进行数千次运行并计算time python foo.pytime python bar.py 的平均值,是否足以对它们的速度进行分析和比较?


编辑: 另外,如果每个程序的执行时间都小于一秒(假设上面不是这种情况),使用 time 命令仍然可以吗?


单次执行的运行时间有多长?如果小于一秒钟,可能会由于精度不足而产生系统误差,而系统误差不会通过平均消除。 - Ben Voigt
1
通常情况下,我会首先对执行时间比第二个长得多的代码进行分析。 - chrisdotcode
此外,即使密集代码具有亚秒执行时间,在程序内执行该操作一百万次左右是否可以减轻系统误差?这样,time将比较一百万次foo和一百万次bar的运行时间。 - chrisdotcode
1
同意。但是例如,从makefile或其他shell脚本调用了一百万次的子秒程序可能值得进行分析,但单独的时间是没有意义的。 - Ben Voigt
4个回答

63

time生成的时间足够好,可以用于运行超过一秒钟的基准测试,否则exec()执行进程所需的时间可能与其运行时间相比较大。

然而,在基准测试时,你应该注意上下文切换。也就是说,另一个进程可能正在使用CPU,从而与你的基准测试竞争CPU资源并增加它的运行时间。为避免与其他进程竞争,你应该像这样运行基准测试:

sudo chrt -f 99 /usr/bin/time --verbose <benchmark>

或者

sudo chrt -f 99 perf stat -ddd <benchmark>

sudo chrt -f 99 命令将以优先级为99的FIFO实时类方式运行您的基准测试,这将使您的进程成为最高优先级进程,并避免上下文切换(您可以更改 /etc/security/limits.conf 文件,以便不需要特权进程即可使用实时优先级)。同时,time 命令将报告所有可用的统计数据,包括您的基准测试所产生的上下文切换次数。通常情况下,这个数字应该是0,否则您可能需要重新运行基准测试。

perf stat -ddd 命令比 /usr/bin/time 更加详细,可以显示指令-周期、分支和缓存丢失等信息。

最好禁用CPU频率调整和增强功能,以保持CPU频率在基准测试期间恒定,以获得一致的结果。


这是最详尽的答案,但如果程序执行时间少于一秒怎么办? - chrisdotcode
谢谢Chris。如果执行时间小于一秒,则其中很大一部分时间可能是通过exec()启动进程。最好进行几秒钟的基准测试运行,以最小化启动时间偏差。 - Maxim Egorushkin

61

现在,我认为没有理由再使用time来进行基准测试。相反,应该使用perf stat。它可以提供更多有用的信息,可以重复任意次数的基准测试过程,并对结果进行统计,例如计算方差和平均值。这更可靠,而且与time一样简单易用:

perf stat -r 10 -d <your app and arguments>

-r 10参数会运行你的程序10次并对其进行统计。-d参数会输出一些额外的数据,例如缓存未命中。

因此,尽管time对于长时间运行的应用程序可能足够可靠,但它绝对不如perf stat可靠。请使用后者。

补充说明:如果你真的想继续使用time,至少不要使用bash内置命令,而是使用详细模式下的真实工具:

/usr/bin/time -v <some command with arguments>

输出结果可能如下:

    Command being timed: "ls"
    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:00.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): 1968
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 93
    Voluntary context switches: 1
    Involuntary context switches: 2
    Swaps: 0
    File system inputs: 8
    File system outputs: 0
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0

特别注意它可以测量RSS峰值,如果您想比较补丁对峰值内存消耗的影响,则通常足够。即使用该值在之前/之后进行比较,如果RSS峰值显着降低,则说明您做得很好。


4
在Debian上,您需要安装linux-tools-$version软件包。 - wieczorek1990
在Ubuntu上安装linux-tools-generic(通过此问题 - Kariem

5

是的,time足够准确。只需要运行程序几次(前提是运行时间超过一秒钟或者显著部分的一秒钟,也就是至少200毫秒),当然,对大多数运行来说(除了第一次),文件系统都会处于热态(即小文件已经缓存在内存中),所以需要考虑这一点。

想要获得高精度和时间测量的粒度,请确保time命令的运行时间至少为几个十分之一秒。不要期望精度低于百分之一秒(你需要某些特殊内核选项才能达到一毫秒的精度)。

从应用程序内部,可以使用clockclock_gettimegettimeofdaygetrusagetimes(它们肯定有Python等效函数)。

不要忘记阅读time(7)手册页。


1
time -d 是什么?我在 Linux 或 OSX 的手册页中没有看到这个参数。 - dfc
2
我指的是形容词“timed”,与time命令有关。 - Basile Starynkevitch

2

是的,time命令提供了经过时间和消耗CPU的信息。除非您正在进行大量I/O操作,否则后者可能是您应该关注的重点。如果经过时间很重要,请确保系统在运行测试时没有其他重要活动。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接