聊聊 top 命令中的 CPU 使用率
扫描二维码
随时随地手机看文章
平常我们使用
top
命令来查看系统的性能情况,在 top
命令中可以看到很多不同类型的 CPU 使用率,如下图红框中标出部分:下面,我们来介绍一下这些 CPU 使用率的意义:
us
:user time,表示 CPU 执行用户进程的时间,包括 nice 时间。通常都是希望用户空间CPU越高越好。sy
:system time,表示 CPU 在内核运行的时间,包括 IRQ 和 softirq。系统 CPU 占用越高,表明系统某部分存在瓶颈。通常这个值越低越好。ni
:nice time,具有优先级的用户进程执行时占用的 CPU 利用率百分比。id
:idle time,表示系统处于空闲期,等待进程运行。wa
:waiting time,表示 CPU 在等待 IO 操作完成所花费的时间。系统不应该花费大量的时间来等待 IO 操作,否则就说明 IO 存在瓶颈。hi
:hard IRQ time,表示系统处理硬中断所花费的时间。si
:soft IRQ time,表示系统处理软中断所花费的时间。st
:steal time,被强制等待(involuntary wait)虚拟 CPU 的时间,此时 Hypervisor 在为另一个虚拟处理器服务。
时钟中断
首先,我们要知道统计 CPU 使用情况在什么地方执行的。在分析之前,我们先来了解下时钟中断
:时钟中断:是一种硬中断,由时间硬件(系统定时器,一种可编程硬件)产生。当 CPU 接收到时钟中断信号后,会在处理完当前指令后调用 时钟中断处理程序
来完成更新系统时间、执行周期性任务等。
可以发现,统计 CPU 使用情况是在 时钟中断处理程序
中完成的。每个 CPU 的使用情况通过 cpu_usage_stat
结构来记录,我们来看看其定义:struct cpu_usage_stat {
cputime64_t user;
cputime64_t nice;
cputime64_t system;
cputime64_t softirq;
cputime64_t irq;
cputime64_t idle;
cputime64_t iowait;
cputime64_t steal;
cputime64_t guest;
};
从 cpu_usage_stat
结构的定义可以看出,其每个字段与 top
命令的 CPU 使用率类型一一对应。在内核初始化时,会为每个 CPU 创建一个 cpu_usage_stat
结构,用于统计 CPU 的使用情况。OK,现在我们来分析下内核是怎么统计 CPU 的使用情况的。每次执行 时钟中断处理程序
都会调用 account_process_tick
函数进行 CPU 使用情况统计,我们来分析一下 account_process_tick
函数的实现:void account_process_tick(struct task_struct *p, int user_tick)
{
cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
struct rq *rq = this_rq();
// 说明:user_tick 变量标识当前是否处于执行用户应用程序
if (user_tick) {
// 1. 如果 CPU 在执行用户程序, 那么调用 account_user_time 进行统计
account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
} else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET)) {
// 2. 如果 CPU 在执行内核代码, 那么调用 account_system_time 进行统计
account_system_time(p, HARDIRQ_OFFSET, cputime_one_jiffy,
one_jiffy_scaled);
} else {
// 3. 否则说明 CPU 在执行 idle 进程(也就是处于空闲状态), 那么调用 account_idle_time 进行统计
account_idle_time(cputime_one_jiffy);
}
}
account_process_tick
函数主要分 3 种情况进行统计,如下:- 如果 CPU 在执行用户程序,那么调用
account_user_time
进行统计。 - 如果 CPU 在执行内核代码,那么调用
account_system_time
进行统计。 - 否则说明 CPU 在执行 idle 进程(也就是处于空闲状态),那么调用
account_idle_time
进行统计。
top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;color: rgb(0, 0, 0);border-bottom: 2px solid rgb(239, 112, 96);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">CPU 使用情况统计
下面我们分别对这 3 种统计进行分析。1. 统计用户程序执行时间
统计用户程序的执行时间是通过account_user_time
函数来完成的,我们来看看其实现:void account_user_time(struct task_struct *p, cputime_t cputime,
cputime_t cputime_scaled)
{
// 获取 CPU 的统计结构(每个CPU一个 cpu_usage_stat 结构)
struct cpu_usage_stat *cpustat =