shell 关键字time
可用于计时一个进程需要多长时间,但time
它本身实际上会给该进程增加多少开销?
换句话说,使用以下命令计时,命令运行速度会慢多少time
:
time grep "a string"
...比没有计时的时候更是如此:
grep "a string"
答案1
初步说明
有时很容易混淆time
实用程序。您明确询问了“shell 关键字time
”。
代码
以下代码将运行测量true
(这是 Bash 中的内置 shell)n次,然后测量true
相同次数。减去相应的结果并除以n。
export n=10000000
time bash -c 'for ((i=1;i<=n;i++)); do time true; done' 2>/dev/null
time bash -c 'for ((i=1;i<=n;i++)); do true; done' 2>/dev/null
例子
我n=10000000
分别得到:
real 1m32.693s
user 1m13.679s
sys 0m18.998s
real 0m39.344s
user 0m39.343s
sys 0m0.000s
各自的区别:
real 53.349s
user 34.336s
sys 18.998s
每人time
:
real 5.3349μs
user 3.4336μs
sys 1.8998μs
分析
这些取决于操作系统的一般和临时速度,因此您的结果会有所不同。我的测试平台是一台配备 i7 CPU、Kubuntu 18.04.3 LTS、Bash 4.4.20 的笔记本电脑。我还有一台速度慢得多的电脑作为家用路由器/服务器。结果如下,,36μs
。现在你知道预期的幅度了。21μs
15μs
我也测试了不同的值n. 总时间表现出良好的线性。换句话说,“每人time
”的结果不依赖于n. 就我的代码而言,这是预料之中的。
结论
time
在我的 Bash 中,测量精度为 1 毫秒。即使在相对较慢的计算机上,开销也小 20 倍以上。我想说这是可以忽略不计的。
奖金
另一个怎么样time
?
在我的笔记本电脑上,我将time
循环中的 替换为/usr/bin/time
(并在两行中都替换为,因为true
无法使用内置函数)。这些是使用 获得的每个结果(略有四舍五入):/bin/true
/usr/bin/time true
true
/usr/bin/time
n=100000
real 600μs
user 530μs
sys 80μs
外部可执行文件比内置可执行文件慢 100 倍左右。实际上,一次调用/usr/bin/time
可能需要更长的时间,因为操作系统可能需要从硬盘读取可执行文件。然后文件被缓存,因此在我的人工测试中,循环的其余部分会受益,并且如果n足够大。
相比之下,time
Bash 提供的速度即使是第一次运行也应该同样快,因为bash
已经加载了(但我还没有测试过)。
回到/usr/bin/time
。我预计在较慢的机器上开销很容易超过 1 毫秒。
答案2
time
您可以通过将其包装到另一个来测试需要花费多少time
:
time time true
注意:我添加的true
是“不执行任何操作”的简单命令。
true - 不执行任何操作,成功 -
man true
在我的电脑上,它显示:
real:0m0.000s user:0m0.000s sys:0m0.000s
即使发生了 20 次:
$ time time time time time time time time time time time time time time time time time time time time true true
real:0m0.000s user:0m0.000s sys:0m0.000s
这里有 1000 个:
$ eval $(for i in $(seq 1 1000); do printf "time "; done) true
real:0m0.000s user:0m0.000s sys:0m0.000s
man time
给出了一些有关如何计算时间的线索:
time 显示的大部分信息来自 wait3(2) 系统调用。这些数字仅与 wait3(2) 返回的数字一样好。在没有 wait3(2) 调用返回状态信息的系统上,将改用 times(2) 系统调用。但是,它提供的信息比 wait3(2) 少得多,因此在这些系统上,time 将大多数资源报告为零。
如需了解更多技术细节,请查看:man 2 wait3
或man wait4
。
要在 Linux 上调试time
,你可以使用strace
,例如
$ strace -f time true
要计算系统调用的时间(-c
)并总结时间差异(-s
),请运行:
$ strace -fwc time true
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
30.91 0.007723 69 112 write
27.19 0.006794 6794 1 wait4
20.44 0.005107 340 15 13 execve
7.43 0.001855 1855 1 clone
2.94 0.000734 122 6 6 access
...
time
以下是调试10次的方法:
$ strace -fwc $(echo $(for i in $(seq 1 10); do printf "time "; done)) true | head
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
87.35 1.057704 105770 10 wait4
7.33 0.088807 79 1120 write
2.25 0.027275 222 123 112 execve
1.37 0.016571 1657 10 clone
0.32 0.003913 71 55 mmap
0.32 0.003844 116 33 33 access
...
1000次之后:
$ strace -fwc $(echo $(for i in $(seq 1 100); do printf "time "; done)) true | head
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
98.66 112.115311 1121153 100 wait4
0.77 0.874091 78 11200 write
0.24 0.271382 226 1203 1102 execve
0.16 0.179477 1795 100 clone
0.03 0.037229 123 303 303 access
0.03 0.036702 73 505 mmap
...
显然在调试器下运行时,运行实际命令时时间会更慢,但它可以大致了解正在使用哪种系统调用以及与其他系统调用相比它们可以使用多少时间。
答案3
原则上,time 所做的只是等待(字面意思是,它会调用 ,从而完全停止自身进程wait3()
的执行)子进程完成,然后向内核询问子进程的资源使用情况统计信息。因此, 几乎不会对子进程的运行时间产生任何影响。time
time
这些统计数据似乎总是被收集。似乎没有“启动监控”模式或会减慢子进程速度的某些东西。我在这里使用“似乎”,因为我无法查看代码,也找不到明确证实这一点的来源。
来源/这个兔子洞的入口:http://man7.org/linux/man-pages/man2/wait4.2.html