linux - bash 内置时间命令的精度是多少?

标签 linux bash performance time

我有一个脚本可以使用 bash 内置命令 time 测量程序的执行时间。

我试图了解此命令的精度:据我所知,它以毫秒为单位返回精度,但它使用 getrusage() 函数返回以微秒为单位的值。但是读this paper ,真正的精度只有 10 毫秒,因为 getrusage 依赖于滴答 (= 100Hz) 对时间进行采样。这篇论文真的很旧(它提到 Linux 2.2.14 运行在具有 96Mb 内存的 Pentium 166Mhz 上)。

time 是否仍在使用 getrusage() 和 100 Hz 滴答或在现代系统上更精确?

测试机运行Linux 2.6.32

编辑:这是muru 的代码 的略微修改版本(应该也可以在旧版本的 GCC 上编译):修改变量 'v' 的值也更改措施之间的延迟,以发现最小粒度。大约 500,000 的值应该在相对较新的 cpu 上触发 1ms 的变化(i5/i7 的第一个版本 @~2.5Ghz)

#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>

void dosomething(){
    long v = 1000000; 
        while (v > 0)
          v--;
}

int main()
{
    struct rusage r1, r2;
    long t1, t2, min, max;
    int i;

    printf("t1\tt2\tdiff\n");

    for (i = 0; i<5; i++){
        getrusage(RUSAGE_SELF, &r1);
        dosomething();
        getrusage(RUSAGE_SELF, &r2);

        t1 = r1.ru_stime.tv_usec + r1.ru_stime.tv_sec*1000000 + r1.ru_utime.tv_usec + r1.ru_utime.tv_sec*1000000;
        t2 = r2.ru_stime.tv_usec + r2.ru_stime.tv_sec*1000000 + r2.ru_utime.tv_usec + r2.ru_utime.tv_sec*1000000;

        printf("%ld\t%ld\t%ld\n",t1,t2,t2-t1);

        if ((t2-t1 < min) | (i == 0))
            min = t2-t1;

        if ((t2-t1 > max) | (i == 0))
            max = t2-t1;
        dosomething();

    }

    printf("Min = %ldus Max = %ldus\n",min,max);

    return 0;
}

然而,精度受限于 linux 版本:对于 Linux 3 及更高版本,精度符合我们的要求,而在 linux 2.6.32 上可能约为 1ms,这可能还取决于特定的发行版。我想这种差异与在最近的 linux 版本上使用 HRT isstead of Tick 有关。

在任何情况下,所有最新和不太新的机器上的最大时间精度为 1 毫秒。

最佳答案

bash 内置 time 仍然使用 getrusage(2)。在 Ubuntu 14.04 系统上:

$ bash --version
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ strace -o log bash -c 'time sleep 1'

real    0m1.018s
user    0m0.000s
sys 0m0.001s
$ tail log
getrusage(RUSAGE_SELF, {ru_utime={0, 0}, ru_stime={0, 3242}, ...}) = 0
getrusage(RUSAGE_CHILDREN, {ru_utime={0, 0}, ru_stime={0, 530}, ...}) = 0
write(2, "\n", 1)                       = 1
write(2, "real\t0m1.018s\n", 14)        = 14
write(2, "user\t0m0.000s\n", 14)        = 14
write(2, "sys\t0m0.001s\n", 13)         = 13
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
exit_group(0)                           = ?
+++ exited with 0 +++

strace 输出所示,它调用 getrusage

关于精度,getrusage 使用的rusage 结构包括timeval 对象,并且timeval 具有微秒精度.来自manpage of getrusage :

ru_utime
      This is the total amount of time spent executing in user mode,
      expressed in a timeval structure (seconds plus microseconds).

ru_stime
      This is the total amount of time spent executing in kernel
      mode, expressed in a timeval structure (seconds plus
      microseconds).

我认为它比 10 毫秒要好。以下面的示例文件为例:

#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>

int main()
{
    struct rusage now, then;
    getrusage(RUSAGE_SELF, &then);
    getrusage(RUSAGE_SELF, &now);
    printf("%ld %ld\n",
        then.ru_stime.tv_usec + then.ru_stime.tv_sec*1000000 + then.ru_utime.tv_usec + then.ru_utime.tv_sec*1000000
        now.ru_stime.tv_usec + now.ru_stime.tv_sec*1000000 + now.ru_utime.tv_usec + now.ru_utime.tv_sec*1000000);
}

现在:

$ make test
cc     test.c   -o test
$ for ((i=0; i < 5; i++)); do ./test; done
447 448
356 356
348 348
347 347
349 350

报告的 getrusage 连续调用之间的差异为 1 µs 和 0(最小值)。由于它确实显示了 1 µs 的间隙,因此刻度必须最多为 1 µs。

如果它有 10 毫秒的滴答声,则差异将为零,或者至少为 10000。

关于linux - bash 内置时间命令的精度是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35289615/

相关文章:

java - 从 map 中查找前 100 个元素的最有效方法

c# - 保存循环或使用 2 种方法 - 约定与性能

linux - 使用 nohup 调用函数

linux - 复制的 bash 脚本文件,文件名中有附加字符

linux - Bash 替换字符串我不希望它这样做

Linux:将 Seiko usb 打印机连接为串口

arrays - 将参数和数组的组合从 linux shell 脚本传递到另一个 shell 脚本

python - 使用开发服务器上的祖先从 AppEngine 数据存储区读取 100 行时出现性能问题。

linux - 易于跨平台脚本编写的语言

linux - 通过文件进行进程间通信