【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