linux命令time介绍
在Linux中,time命令用于测量命令的执行时间,精确到毫秒级。它提供三个关键指标:实际时间(real)、用户态时间(user) 和 内核态时间(sys)。有时候我们需要对比两个实现相同功能的接口哪个效率更高,例如评估两个算法,谁执行消耗的时间更少。我们通常会用time命令快速评估。time命令默认的输出格式为:
thammer@exc:~/test/empty$ time ls
real 0m0.001s
user 0m0.000s
sys 0m0.001s
核心时间指标
| 指标 | 说明 |
|---|---|
| real | 命令从开始到结束的实际耗时(墙钟时间Wall time),包括等待I/O、CPU调度等时间 |
| user | 进程在用户态(User Mode) 消耗的CPU时间,即程序自身的代码执行时间 |
| sys | 进程在内核态(Kernel Mode) 消耗的CPU时间,如系统调用、内核操作时间 |
解释一下,所谓墙钟时间就是指不受其他因素影响,永远是递增的时间,为啥要提出这么个概念,就是因为如果用系统时间差值,那么系统时间是会被诸如NTP,用户命令修改的,导致结果可能不准。
一个程序运行所消耗的时间包括:CPU执行时间 + I/O时间 + 系统调度时间 + 资源冲突等待时间(各种锁)+ 缓存等待时间
real、user、sys能反应出什么?
Real = User + Sys + ∑(非CPU开销)
其中:
- User: 用户态CPU时间
- Sys: 内核态CPU时间
- 非CPU开销 ≈ I/O等待 + 调度延迟 + 资源竞争延迟 + 外部依赖时间
I/O密集型程序:
real >> user + sys,典型的例子是大文件拷贝:
time cp bigfile destfile
real 0m8.653s
user 0m0.000s
sys 0m2.862s
real远大于user + sys并不一定说明程序就是I/O密集型,因为上面的公式表明上面的输出大部分时间被非CPU开销消耗。而非CPU开销包括:I/O + 调度 + 资源竞争 + 外部依赖。通常调度不会消耗太多时间。
CPU密集型程序:
real ≈ user + sys,典型的例子是加解密,计算哈希,软解码等这类程序。
time sha256sum bigfile
e33d7b1ea7a9e2f38c8f693215dd85254c3a4fe446f93f563279715b68d07987 bigfile
real 0m8.947s
user 0m8.553s
sys 0m0.386s
如果user >> sys说明消耗CPU时间的在用户空间,例如我们自己的接口和库接口。
如果sys >> user说明消耗CPU时间的在内核空间, 例如频繁的系统调用。例如:
for (int i = 0; i < 1000000; ++i)
{
int fd = open("file.txt", O_RDONLY);
close(fd);
}
open和close均为系统调用,所有大部分时间消耗在了sys。
多线程程序:
real < user + sys,如果发现实际总耗时小于user + sys的情况,那说明这是一个CPU密集型的多线程程序。为什么呢?因为user和sys统计的是进程内所有线程的耗时,假设每个CPU都干一模一样的活,那么1s内,可以统计出N个线程各自消耗1秒(理想状态),也就是real(1s), user + sys(N s)。可以看下图理解:
time命令原理
-
- 时间测量机制:
-
时间源:现代CPU通过RDTSC(Read Time-Stamp Counter)指令,直接从处理器获取纳秒级计时
-
双时钟系统:
- real time:基于CLOCK_MONOTONIC(单调递增时钟,不受NTP影响)
- user/sys time:基于CLOCK_PROCESS_CPUTIME_ID(进程级CPU时钟)
-
- 资源监控机制,通过wait4()系统调用获取:
- struct rusage:包含CPU时间、内存、IO等20+项指标
- /proc/pid/stat:内核暴露的进程实时状态
time命令更多测量参数
Shell内置time和GUN time
在ubuntu22.04下:
thammer@exc:~$ type -a time
time 是 shell 关键字
time 是 /usr/bin/time
time 是 /bin/time
可以看到time命令有三个,一个是shell内置的,另外两个实际是一个文件,/bin 是指向/usr/bin的符号链接。shell(ubuntu22.04上是bash)内置的time命令仅包含精简功能,/usr/bin/time是GUN版本time,man time实际是它的手册,而非bash内置的time。内置time好处是直接在当前bash进程执行测量流程,GNU time还需要额外开个进程执行time xxx命令执行测量流程,可以提高一点点精度。
man time的翻译:
TIME(1) 通用命令手册
名称
time - 运行程序并汇总系统资源使用情况
语法
time [ -apqvV ] [ -f FORMAT ] [ -o FILE ]
[ --append ] [ --verbose ] [ --quiet ] [ --portability ]
[ --format=FORMAT ] [ --output=FILE ] [ --version ]
[ --help ] COMMAND [ ARGS ]
描述
time 运行程序 COMMAND 并带有给定的参数 ARG...。当 COMMAND 结束时,time 显示有关 COMMAND 使用的资源信息(默认输出到标准错误输出)。如果 COMMAND 以非零状态退出,time 会显示警告消息和退出状态。
time 根据字符串 FORMAT 确定要显示的关于 COMMAND 使用的资源信息。如果命令行上没有指定格式,但设置了 TIME 环境变量,则使用其值作为格式。否则,使用内置到 time 中的默认格式。
time 的选项必须出现在命令行上的 COMMAND 之前。命令行上 COMMAND 之后的任何内容都作为参数传递给 COMMAND。
选项
-
-o FILE, --output=FILE
将资源使用统计信息写入 FILE 而不是标准错误流。默认情况下,这会覆盖文件,销毁文件的先前内容。此选项对于收集交互式程序和产生标准错误流输出的程序的信息很有用。 -
-a, --append
将资源使用信息追加到输出文件而不是覆盖它。此选项仅在与-o或--output选项一起使用时有用。 -
-f FORMAT, --format FORMAT
使用 FORMAT 作为控制 time 输出的格式字符串。请参阅下面的更多信息。 -
--help
打印命令行选项摘要并退出。 -
-p, --portability
使用以下格式字符串,以符合 POSIX 标准 1003.2:real %e user %U sys %S -
-v, --verbose
使用内置的详细格式,该格式在单独的行上显示程序资源使用的每个可用信息,并带有其含义的英文描述。 -
--quiet
即使程序状态与零不同,也不报告程序状态。 -
-V, --version
打印 time 的版本号并退出。
格式化输出
格式字符串 FORMAT 控制 time 输出的内容。可以使用 -f 或 --format、-v 或 --verbose、或 -p 或 --portability 选项设置格式字符串。如果未给出这些选项,但设置了 TIME 环境变量,则使用其值作为格式字符串。否则,使用内置的默认格式。默认格式为:
%Uuser %Ssystem %Eelapsed %PCPU (%Xtext+%Ddata %Mmax)k
%Iinputs+%Ooutputs (%Fmajor+%Rminor)pagefaults %Wswaps
格式字符串通常由散布着纯文本的"资源说明符"组成。格式字符串中的百分号(%)使以下字符被解释为资源说明符,类似于 printf(3) 函数中的格式化字符。
反斜杠(\)引入"反斜杠转义",在输出时转换为单个打印字符。\t 输出制表符,\n 输出换行符,\\ 输出反斜杠。反斜杠后跟任何其他字符输出问号(?)后跟反斜杠,表示给出了无效的反斜杠转义。
格式字符串中的其他文本按原样复制到输出。time 在打印资源使用信息后总是打印换行符,因此通常格式字符串不以换行符(或 \n)结尾。
有许多资源说明符。并非所有版本的 Unix 都测量所有资源,因此某些值可能报告为零。百分号后跟的未在下表中列出的任何字符都会导致输出问号(?),后跟该字符,表示给出了无效的资源说明符。
资源说明符(它们是 tcsh(1) 内置 time 命令识别的超集)包括:
%:字面量%C:正在计时的命令的名称和命令行参数D:进程未共享数据区域的平均大小,以千字节为单位E:进程使用的经过的实际(挂钟)时间,格式为 [小时:]分:秒F:进程运行期间发生的主要或需要 I/O 的页面错误数。这些是页面实际上已从主内存迁移出去的错误I:进程的文件系统输入数K:进程的平均总(数据+堆栈+文本)内存使用量,以千字节为单位M:进程在其生命周期内的最大常驻集大小,以千字节为单位O:进程的文件系统输出数P:此作业获得的 CPU 百分比。这只是用户时间 + 系统时间除以总运行时间。它还打印百分号R:次要或可恢复的页面错误数。这些是无效的页面(因此它们出错),但尚未被其他虚拟页面声明。因此页面中的数据仍然有效,但系统表必须更新S:系统代表进程使用的 CPU 秒总数(内核模式),以秒为单位U:进程直接使用的 CPU 秒总数(用户模式),以秒为单位W:进程从主内存换出的次数X:进程中共享文本的平均量,以千字节为单位Z:系统的页面大小,以字节为单位。这是每个系统的常量,但在系统之间有所不同c:进程非自愿上下文切换的次数(因为时间片到期)e:进程使用的经过的实际(挂钟)时间,以秒为单位k:传递给进程的信号数p:进程的平均未共享堆栈大小,以千字节为单位r:进程接收的套接字消息数s:进程发送的套接字消息数t:进程的平均常驻集大小,以千字节为单位w:程序自愿上下文切换的次数,例如在等待 I/O 操作完成时x:命令的退出状态
示例
要运行命令 wc /etc/hosts 并显示默认信息:
time wc /etc/hosts
要运行命令 ls -Fs 并仅显示用户、系统和总时间:
time -f "\t%E real,\t%U user,\t%S sys" ls -Fs
要编辑文件 BORK 并让 time 将经过的时间和信号数追加到文件 log,从环境变量 TIME 读取格式字符串:
export TIME="\t%E,\t%k" # 如果使用 bash 或 ksh
setenv TIME "\t%E,\t%k" # 如果使用 csh 或 tcsh
time -a -o log emacs bork
bash shell 的用户需要使用显式路径来运行外部 time 命令而不是 shell 内置变体。在 time 安装在 /usr/bin 的系统上,第一个示例将变为:
/usr/bin/time wc /etc/hosts
准确性
经过的时间不是与程序的执行原子性地收集的;因此,在奇怪的情况下(如果 time 命令在正在计时的程序退出和 time 计算运行所需时间之间被停止或换出),它可能比实际执行时间大得多。
当命令的运行时间非常接近零时,某些值(例如,使用的 CPU 百分比)可能报告为零(这是错误的)或问号。
time 显示的大多数信息都来自 wait3(2) 系统调用。这些数字与 wait3(2) 返回的数字一样好。在没有返回状态信息的 wait3(2) 调用的系统上,使用 times(2) 系统调用代替。但是,它提供的信息比 wait3(2) 少得多,因此在那些系统上 time 将大部分资源报告为零。
%I 和 %O 值据称只是"真实"的输入和输出,不包括缓存设备提供的输入和输出。%I 和 %O 报告的"真实" I/O 的含义对于工作站,特别是无盘工作站,可能会混淆。
诊断
time 命令在程序退出、停止或被信号终止时返回。如果程序正常退出,time 的返回值是它执行和测量的程序的返回值。否则,返回值是 128 加上导致程序停止或终止的信号编号。
作者
time 由 David MacKenzie 编写。此手册页由 Debian GNU/Linux 维护者 Dirk Eddelbuettel edd@debian.org 添加,供 Debian GNU/Linux 发行版使用,但当然也可以被其他人使用。
另请参阅
tcsh(1), printf(3)

浙公网安备 33010602011771号