由于自己使用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的和“之间没有任何关系。