【Linux】命令 - time

Posted by 西维蜀黍 on 2018-11-06, Last Modified on 2022-12-10

由于自己使用 macOS,因此以下所有测试都 macOS 下进行。而 macOS 中的 time 与 Linux 中的 time 命令是几乎几乎完全相同的。

Demo

我们执行一个 node 任务,并测试它的耗时:

$ time node main.js
node main.js  4.95s user 0.06s system 97% cpu 5.139 total

我们得到了 4 个数字,接下来分别来解释:

4.95s user

0.06s system

97% cpu

5.139 total

total

5.139 total 最为简单,表示整个任务执行的总时长,即当开始执行 node main.js 的那一刻,我们看了一下手表,再执行结束时,又看了一下手表。两次时间的差值就为 total 的值。

一句话概括,total 表示该任务进行的绝对时长。

在 Linux 中,real 值即对应这里的 total 值。比如,在 Linux 中执行一次 time 命令:

$time file1
real        0m0.003s
user        0m0.000s
sys         0m0.004s

执行一个较为特殊的例子:

$ time sleep 2
sleep 2  0.00s user 0.00s system 0% cpu 2.008 total

sleep 2 会让当前进程的主线程休眠 2 秒,可以看到这个进程总共存活了 2.008 秒。


在介绍 user 值和 system 值之前,我们先介绍两个概念。

内核态(Kernel Mode)

在内核态时,当前执行的代码拥有完全的、不受限制的访问底层硬件(underlying hardware)的能力。它可以执行任何 CPU 指令或者引用任何内存地址。当处在内核态时,通常都在执行由操作系统提供的最底层的、可靠的代码。

如在处在内核态时,发生了崩溃,这将会是灾难性的,因为这个崩溃会影响整个操作系统的运行。

用户态(User Mode)

在用户态时,当前执行的代码不具备直接访问底层硬件或内存的能力。代码必须通过调用操作系统 API(通常是系统调用,System Call)来访问底层硬件或内存。

通过因此内核态和用户态的隔离机制,使得处于用户态的崩溃都可以被恢复。

我们的大部分代码都运行在用户态状态下。


引入了上述概念后,这两个值就非常容易理解了。

user

user time,即一个进程执行过程中,代码处于用户态过程所经历的 CPU 时间。

system

system time,即一个进程执行过程中,代码处于内核态过程所经历的 CPU 时间。

cpu

即 CPU 利用率(CPU usgae),即在一个进程执行过程中,CPU 的利用率。

CPU_usage = (user time + system time)/ total time * 100%


在上面 node 的例子中:

  • 4.95s user
  • 0.06s system
  • 97% cpu
  • 5.139 total

(4.95 + 0.06)/5.139 = 97.489784% 约等于 97%,因此,我们认为这个进程的执行过程中,CPU 的利用率很高。


sleep 2 的例子中

  • 0.00s user
  • 0.00s system
  • 0% cpu
  • 2.008 total

(0.00 + 0.00)/2.008 = 0%,即 CPU 的利用率为 0,事实上,这个进程中的主线程仅仅的休眠了 2s,此后这个进程就被结束了。

这个过程中,不存在任何处于用户态和内核态的执行代码。

误区解释

误区 1:total_time = user_time + sys_time

这显然是不对的,比如在前面的 sleep 2 的例子中,2.008 ≠ 0.00 + 0.00。

误区 2:total_time > user_time + sys_time

这不是绝对正常的。只是在大部分单线程执行的情况下,往往都会呈现 total_time > user_time + sys_time

比如在上面 node 的例子中,就符合了 total_time > user_time + sys_time 的情景。

5.139 > 5.01 = 4.95 + 0.06

然而,在使用多线程 / 多进程执行一个应用时,就可能会出现 total_time < user_time + sys_time

比如,以下的 Node 的程序中,通过使用 cluster 模块同时开启八个进程,就出现了 total_time < user_time + sys_time 的情况。

var cluster = require('cluster');
var numCPUs = 8;
function fibo (n) {
  return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
}

console.time('8 cluster');
if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  var i = 8;
  cluster.on('exit', function(worker, code, signal) {
    if(!--i){
      console.timeEnd('8 cluster');
      process.exit(0);
    }
  });
} else {
  //console.log(fibo (40));
  process.exit(0);
}

使用 time

$ time node main.js
8 cluster: 3126.211ms
node main.js  21.71s user 0.34s system 684% cpu 3.221 total

结论

“total_time” 与 ”user_time + sys_time 的和 “之间没有任何关系。

Reference