Linux中CPU利用率是如何计算出来的?(PS:top命令背后的技术细节)

1,038 阅读6分钟

1. CPU占用率计算原理

1.1 相关概念

在Linux/Unix 下,CPU 利用率分为用户态、系统态和空闲态,分别表示CPU 处于用户态执行的时间,系统内核执行的时间以及空闲系统进程执行的时间。

我们在控制台输入top命令看到的CPU占有率及其它各项信息,一般我们使用top指令来查看系统的内存状态是否良好。

image.png

下面列举下top命令输出的几个重要信息的含义。

1、用户时间(User time):表示CPU执行用户进程的时间(包括nices时间)。

2、系统时间(System time):表示CPU在内核运行的时间,包括IRQ和softirq时间(PS: 系统CPU占用率高,一般表示系统IO比较高)。

3、等待时间(Waiting time):CPU在等待I/O操作完成所花费的时间(PS: 系统花费大量时间来等待I/O操作,说明I/O存在瓶颈)。

4、空闲时间(Idle time):系统处于空闲期,等待cpu时间片被分配。

5、Nice时间(Nice time):系统处理硬中断花费的时间。

6、软中断处理时间(SoftIrq time):系统处理软中断中断所花费的时间。

7、丢失时间(Steal time):被强制等待(involuntary wait)的虚拟CPU的时间。

1.2 CPU占用率计算

Linux CPU占用率计算,都是根据/proc/stat文件内容计算而来,下面是笔者ubuntu系统stat文件内容的示例:

image.png

第一行cpu为总的信息。cpu0—cpu3为各CPU的具体信息,以第一行CPU信息为例: cpu 9205363 13885432 6622734 29151336 12300 0 13423 0, 这几个值分别表示的含义如下:

image.png

好,了解完上述的概念,笔者在阐述下CPU占有率的计算公式: CPU时间 = user + system + nice + idle + iowait + irq + softirq + Stl

%us = (User time + Nice time)/CPU时间*100%

%sy = (System time + Hard Irq time +SoftIRQ time) / CPU时间*100%

%id = (Idle time)/CPU 时间*100%

%ni=(Nice time)/CPU 时间*100%

%wa = (Waiting time) / CPU时间*100%

%hi = (Hard Irq time) / CPU 时间*100%

%si = (SoftIRQ time) / CPU时间*100%

%st = (Steal time) / CPU时间*100%

2. CPU占有率内核实现

下面以Linux内核源码版本2.6.32-220.el6 x86_64为例,来介绍操作系统内核是如何计算cpu利用率的。/proc/stat文件的创建由函数proc_stat_init()实现,在文件fs/proc/stat.c中。内核初始化时会调用该接口。/proc/stat文件相关函数实现均在stat.c文件中。对/proc/stat 文件的读写方法为proc_stat_operations。

image.png

打开文件函数为stat_open(),函数首先申请大小为size的内存,来存放临时数据(也是我们看到的stat里的最新数据)。

image.png

image.png

/proc/stat文件数据由show_stat()函数填充。注意00042行的for_each_possible_cpu()循环,是累加计算所有CPU的数据,正是上文提到的/proc/stat文件中第一行cpu值

cpu 9205363 13885432 6622734 29151336 12300 0 13423 0

image.png

image.png

计算总的CPU的user、nice、system、idle、iowait、irq、softirq、steal时间后,再分别计算各个CPU 的使用情况(00075~00100行)。

image.png

image.png

00104行计算所有CPU上中断次数,00104~00105行计算CPU上每个中断向量的中断次数。注意:/proc/stat文件中,将所有可能的NR_IRQS个中断向量计数都记录下来,但我们的机器只是用少量的中断向量,这就是看到/proc/stat文件中,intr一行后面很多值为0的原因。

show_stat()函数最后获取进程切换次数nctxt、内核启动的时间btime、 所有创建的进程processes、正在运行进程的数量procs_running、阻塞的进程数量procs_blocked以及所有等待IO的进程数量。

image.png

image.png

3.Linux CPU占有率精确性分析

在使用类似top命令,观察系统及各进程CPU占用率时,可以指定刷新时间间隔,以及时刷新和实时观察CPU占用率。top命令默认情况下是每3秒刷新一次。也可以通过top -d 刷新时间间隔来指定刷新频率,如:

top -d 0.1

也可以按S键,修改时间间隔。

我们可以将CPU占用率刷新间隔设置很低,比如:0.01 秒。但过低的刷新频率是否能够更准确观察到CPU 占用率?Linux系统提供的CPU占用率信息是否足够精确?

根据前面分析,我们已知 Linux 是根据/proc/stat 文件的内容来计算CPU占用率,也就是精确度和/proc/stat提供的数据精确度有关。那么:

(1)/proc/stat 文件中的内容单位是什么?

(2)多久会刷新/proc/stat 中的数据?

带着这两个疑问,请接着往下看

3.1 /proc/stat中的数据单元精度

/proc/stat中CPU数据信息,单位是ticks。内核中有个全局变量jiffies ,来记录系统启动以来,经历的ticks数量。 cpu1 13 0 200 368639 63 0 0 0 0

ticks(滴答)就是系统时钟中断的间隔,该值与内核中HZ值有关,即ticks = 1/HZ。HZ值的大小,在内核编译时可配置的。笔者ubuntu系统的内核,配置的HZ值为1000。

image.png HZ值,就是每秒的时钟中断数量。可以观察/proc/interrupts 中时钟中断值变化,来计算HZ的值。当HZ的值为1000时,ticks的单位即为1/1000秒,即1ms 。

image.png

3.2 CPU利用率统计信息更新

在时钟中断程序中,更新CPU 利用信息,即每个ticks 更新一次。include/linux/kernel_stat.h 中,有相应函数接口,专门用来更新CPU 利用率信息。如account_user_time()是更新用户态CPU 信息。

image.png

image.png

每次时钟中断时(ticks),就会更新kernel_stat变量中各个成员变量的值。/proc/stat文件中的值,都是在程序读取时更新,内核并不会主动更新/proc/stat中的数据。/proc/stat中的CPU信息是通过kernel_stat各个成员变量的值计算而来。

3.3 CPU利用率精确性分析

通过前面分析,我们可以得出以下结论:

1、Linux CPU 占用率是根据/proc/stat文件中的数据计算而来;

2、/proc/stat 中的数据精度为ticks ,即1/HZ秒;

3、内核每个ticks 会更新一次CPU 使用信息;

4、CPU 占用率的精度为1/HZ秒。