脚本的运行时间差异很大。我想找到与Matlab的timeit类似的时间函数,描述这里。
例如,我正在评估这些命令这里关于快速计数匹配,time LC_ALL=C grep -ao CDA r328_0002.raw | wc -l
循环运行
---------------------------------------------
Events real user sys
----------- ----------- ----------- ---------
40 0m0.044s 0m0.042s 0m0.005s
40 0m0.064s 0m0.062s 0m0.005s
40 0m0.046s 0m0.044s 0m0.005s
40 0m0.043s 0m0.042s 0m0.005s
40 0m0.047s 0m0.044s 0m0.005s
---------------------------------------------
Table: Events when Macbook Air 2013-Mid in Power Supply.
---------------------------------------------
Events real user sys
----------- ----------- ----------- ---------
40 0m0.056s 0m0.041s 0m0.011s
40 0m0.060s 0m0.047s 0m0.008s
40 0m0.041s 0m0.039s 0m0.006s
40 0m0.046s 0m0.044s 0m0.006s
40 0m0.047s 0m0.045s 0m0.006s
---------------------------------------------
Table: Events when Macbook Air in Battery Supply, 6h later.
您可以看到实时从 0.044s 波动到 0.064s,用户时间从 0.042s 波动到 0.062s,而系统时间保持稳定在 0.005s。我对时间的想法
- 在计时之前先迭代命令 1k
- 计时10次,取平均值和标准差
粗壮到 /dev/nul
这个想法在lcd047的评论中,time LC_ALL=C ggrep -ao CDA r328_0002.raw >/dev/null
循环运行
--------------------------------------------
real user sys
-------------- -------------- ------------
0m0.006s 0m0.003s 0m0.002s
0m0.006s 0m0.003s 0m0.002s
0m0.006s 0m0.003s 0m0.002s
0m0.008s 0m0.003s 0m0.003s
0m0.006s 0m0.003s 0m0.002s
0m0.005s 0m0.002s 0m0.002s
0m0.006s 0m0.002s 0m0.002s
0m0.009s 0m0.003s 0m0.003s
0m0.007s 0m0.003s 0m0.003s
0m0.006s 0m0.003s 0m0.002s
0m0.006s 0m0.003s 0m0.002s
0m0.008s 0m0.003s 0m0.003s
--------------------------------------------
Table: Events when Macbook Air 2013-Mid in Battery Supply.
我认为,当笔记本电脑保持供电并保持较少的程序运行时,这些时间可以得到更大的改善。
如何稳定地计时 shell 脚本?
答案1
答案是:不可以! Linux 不是实时系统。 UNIX 以及 Linux 的理念都是提供最短的应答时间,同时系统在多个用户和系统进程之间共享。根据启动命令的时间,您可能必须等待重要的系统进程才能为您分配处理器时间。此外,文件系统可能会缓冲从磁盘读取的文件,但最终,当系统上的另一个进程占用该文件时,这些文件系统缓冲区无法从缓存加载数据。一般来说,Linux 系统中的进程所需的时间取决于机器周围的熵,无论它位于宇宙的时间和空间中的哪个位置。
您将需要一个实时系统和专门实时调整的命令以及仅为您保留的特定数量的资源。您可能会通过较新内核的新 CGROUP 功能获得接近的效果,您可以在其中为您的环境保留一个处理器、一部分内存以及底层文件系统的自身反映。
您的示例中的主要计时问题之一是 grep 和 wc 读取输入的方式。当您将文件复制到 ramfs 并在那里工作时,也许可以使计时更加稳定。
答案2
首先,您需要了解 shell 脚本只是您自己键入命令的便捷简写。每次您或脚本调用 时grep
,您并不是在调用内置原语;而是在调用 。你要求 shell 寻找一个名为 的程序grep
并将其作为一个新进程启动。在任何未进行可预测性调整的环境中,创建新进程并运行其第一段代码可能是最不可预测的事情。对于任何运行非实时操作系统的计算机来说都是如此。为什么会出现这种情况的细节将成为操作系统半学期课程的素材,但我可以给你举一两个例子来说明为什么你精确测量完整程序执行的努力不会产生你认为一致的结果他们应该。
大多数程序在第一次获得 CPU 时所做的第一件事就是生成页面错误,以便可以加载第一页的代码。如果有十几个其他程序在代码所在的同一设备上执行 I/O,则加载程序页面所需的时间取决于请求在设备队列中的位置。您可能认为您的测试程序是单独运行的,但我敢打赌,事实并非如此。 (还值得一提的是,这grep
是一个 I/O 密集型程序,因此读取输入所需的时间因许多相同的原因而异。)
许多操作系统采取措施避免同时驻留相同代码的冗余副本,以此来减少内存消耗并提高性能。这意味着,如果您启动grep
并且有另一个grep
正在运行且其第一页已驻留,则上述页面错误永远不会发生并且所有这些工作都会被跳过。这会减少挂钟的运行时间。
当您开始timeit
在 MATLAB 中执行 a 时,MATLAB 进程已经在运行,并且在重复调用函数之前它可能会跳过必要的环节来加载您的函数。调用发生得相当快,因为它只是内部调用。虽然还有很多因素会影响timeit
跑步所需的时间,但它们同样适用于其他任何事情。
也就是说,我认为您所看到的真正原因是这种比较不是同类比较。
Unixtime(1)
只运行一次被测试的程序,而 MATLAB 则对timeit
您正在测试的函数进行多次乘以并返回结果的中值。文档建议和和timeit
函数不应一起使用,这暗示后者被前者使用。和的文档建议,如果您的代码运行时间少于 0.1 秒,则运行它多次并计算平均值。我从中得出的结论是,MATLAB 的计时比 的精确度低两个数量级,更多的是用于检查您能够从长时间运行的函数中节省多少时间。如果有足够的样本,那么平均和中值的结合将把大量的变化推向相当一致的结果。tic
toc
tic
toc
time(1)