如何在Linux上使用TIME命令

想知道流程运行多长时间以及更长时间吗?Linux time命令返回时间统计信息,让您可以很好地洞察程序使用的资源。

时间有很多亲戚

有许多Linux发行版和不同的类Unix操作系统。其中每一个都有一个默认的命令shell。现代Linux发行版中最常见的默认shell是bash shell。但是还有很多其他的,比如Zshell(Zsh)和Korn shell(Ksh)。

所有这些shell都包含了它们自己的时间命令,或者作为内置的时间命令,或者作为保留字。当您在终端窗口中键入time时,shell将执行其内部命令,而不是使用作为Linux发行版一部分提供的GNU time二进制文件。

我们希望使用GNU版本的Time,因为它有更多的选择,也更灵活。

几点开始?

您可以使用type命令检查将运行哪个版本。类型将让您知道shell是自己处理您的指令及其内部例程,还是将其传递给GNU二进制文件。

在终端窗口中,键入单词type、空格,然后键入单词time并按Enter。

type time

我们可以看到,在bash shell中,time是一个保留字。这意味着Bash将默认使用其内部时间例程。

type time

在Zshell(Zsh)中,时间是保留字,因此默认情况下将使用内部shell例程。

type time

在Korn shell中,时间是一个关键字。将使用内部例程而不是GNU时间命令。

相关:什么是ZSH,为什么要使用它而不是Bash?

运行GNU时间命令

如果您的Linux系统上的shell有一个内部时间例程,如果您希望使用GNU时间二进制,则需要明确说明。您必须执行以下任一操作:

提供二进制文件的完整路径,如/usr/bin/time。运行Which Time命令查找此路径。 使用命令时间。 使用反斜杠,如\time。

What Time命令为我们提供了二进制文件的路径。

我们可以通过使用/usr/bin/time*作为命令启动GNU二进制文件来测试这一点。真管用。我们从time命令得到响应,告诉我们没有为它提供任何命令行参数。

键入命令time也有效,我们从time获得相同的用法信息。命令命令告诉shell忽略下一个命令,以便在shell外部处理该命令。

在命令名之前使用\字符与在命令名之前使用命令相同。

确保使用GNU时间二进制的最简单方法是使用反斜杠选项。

time\time

时间调用时间的外壳版本。\Time使用时间二进制。

使用TIME命令

让我们给一些节目计时吧。我们使用两个名为loop1和loop2的程序。它们是从loop1.c和loop2.c创建的。除了演示一种类型的编码低效的影响外,它们没有做任何有用的事情。

这是loop1.c。字符串的长度在两个嵌套循环内是必需的。长度是在两个嵌套循环之外预先获得的。

#include "stdio.h" #include "string.h" #include "stdlib.h" int main (int argc, char* argv[]) { int i, j, len, count=0; char szString[]="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek"; // get length of string once, outside of loops len = strlen( szString ); for (j=0; j<500000; j++) { for (i=0; i < len; i++ ) { if (szString[i] == '-') count++; } } printf("Counted %d hyphens\n", count); exit (0); } // end of main

这是loop2.c。对于外环的每个周期,一次又一次地获得字符串的长度。这种低效应该在计时中体现出来。

#include "stdio.h" #include "string.h" #include "stdlib.h" int main (int argc, char* argv[]) { int i, j, count=0; char szString[]="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek"; for (j=0; j<500000; j++) { // getting length of string every // time the loops trigger for (i=0; i < strlen(szString); i++ ) { if (szString[i] == '-') count++; } } printf("Counted %d hyphens\n", count); exit (0); } // end of main

让我们启动loop1程序并使用时间来测量其性能。

\time ./loop1

现在,让我们对loop2执行同样的操作。

\time ./loop2

这给了我们两组结果,但它们的格式真的很难看。我们稍后可以对此做些什么,但让我们从结果中挑选一些信息。

当程序运行时,它们可以在两种执行模式之间来回切换。这些模式称为用户模式和内核模式。

简而言之,处于用户模式的进程不能直接访问其自身分配之外的硬件或引用内存。为了访问这些资源,进程必须向内核发出请求。如果内核批准该请求,则进程进入内核模式执行,直到满足要求。然后将该进程切换回用户模式执行。

loop1的结果告诉我们,loop1在用户模式下花费了0.09秒。或者它在内核模式下花费的时间为零,或者在内核模式下的时间太低,一旦四舍五入就无法注册。总运行时间为0.1秒。在其总运行时间的持续时间内,Loop1平均获得89%的CPU时间。

效率低下的loop2程序的执行时间是原来的三倍。它的总运行时间是0.3秒。用户模式下的处理时间持续时间为0.29秒。没有注册内核模式。在运行期间,Cloop2的平均CPU时间为96%。

格式化输出

您可以使用格式字符串自定义Time的输出。格式字符串可以包含文本和格式说明符。可以在Time手册页上找到格式说明符的列表。每个格式说明符表示一条信息。

打印字符串时,格式说明符将替换为它们表示的实际值。例如,CPU百分比的格式说明符是字母P。要向TIME表明格式说明符不只是一个普通字母,请在其上添加一个百分号,如%P。让我们在一个示例中使用它。

-f(格式字符串)选项用于告诉时间后面的是格式字符串。

我们的格式字符串将打印字符“Program:”和程序名(以及您传递给程序的任何命令行参数)。%C格式说明符代表“正在计时的命令的名称和命令行参数”。\n会使输出移到下一行。

有很多格式说明符,它们是区分大小写的,所以当您自己这样做时,请确保您正确地输入了它们。

接下来,我们将打印字符“Total Time:”,后跟此程序运行的总运行时间的值(由%E表示)。

我们用\n给出另一个新行。然后,我们将打印字符“User Mode(S)”,后跟在用户模式下花费的CPU时间的值,用%U表示。

我们用\n给出另一个新行。这一次,我们正在为内核时间值做准备。我们打印字符“Kernel Mode(S)”,后跟在内核模式中花费的CPU时间的格式说明符,即%S。

最后,我们将打印字符“\nCPU:”,为我们提供一个新行和该数据值的标题。%P格式说明符将给出计时进程使用的CPU时间的平均百分比。

整个格式字符串用引号括起来。如果我们对值的对齐很挑剔,我们可以在输出中包含一些\t个字符来放置制表符。

\time -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop1

将输出发送到文件

要保留您所执行的测试的计时记录,您可以不时地将输出发送到一个文件。为此,请使用-o(输出)选项。您的程序的输出仍将显示在终端窗口中。只有Time的输出才会重定向到文件。

我们可以重新运行测试并将输出保存到test_result ts.txt文件,如下所示:

\time -o test_results.txt -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop1cat test_results.txt

loop1程序输出显示在终端窗口中,并将结果保存到test_result ts.txt文件中。

如果要捕获同一文件中的下一组结果,则必须使用-a(追加)选项,如下所示:

\time -o test_results.txt -a -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop2cat test_results.txt

现在,我们使用%C格式说明符在格式字符串的输出中包含程序名称的原因应该很明显了。

我们没时间了

对于程序员和开发人员来说,最有用的可能是微调代码时使用的time命令,对于希望在每次启动程序时更多地了解幕后情况的人来说,time命令也很有用。

相关文章