聊聊 top 命令中的 CPU 使用率

之前写过cpu占用率的文章

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 进行统计。

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 = &kstat_this_cpu.cpustat; cputime64_t tmp;...// 分 2 种情况统计 CPU 的使用情况// 1. 如果进程的 nice 值大于0, 那么将会统计到 nice 字段中// 2. 如果进程的 nice 值小于等于0, 那么将会统计到 user 字段中if (TASK_NICE(p) > 0)cpustat->nice = cputime64_add(cpustat->nice, tmp);elsecpustat->user = cputime64_add(cpustat->user, tmp);...
}

account_user_time 函数主要分两种情况统计:

  • 如果进程的 nice 值大于0,那么将会增加到 CPU 统计结构的 nice 字段中。

  • 如果进程的 nice 值小于等于0,那么增加到 CPU 统计结构的 user 字段中。

这里说明一下进程 nice 值的作用,nice 值越大,说明进程的优先级越低。所以,nice 统计值主要用来统计低优先级进程的占使用 CPU 的情况。也说明了,user 和 nice 统计值都属于执行用户程序的 CPU 时间。

2. 统计内核代码执行时间

如果在发生时钟中断前,CPU 处于内核态,也就是说在执行内核代码。那么将会调用 account_system_time 函数进行统计,account_system_time 函数实现如下:

void account_system_time(struct task_struct *p, int hardirq_offset,cputime_t cputime, cputime_t cputime_scaled)
{// 获取 CPU 的统计结构(每个CPU一个 cpu_usage_stat 结构)struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;cputime64_t tmp;...// 主要分 3 种情况进行统计// 1. 如果当前处于硬中断执行上下文, 那么统计到 irq 字段中// 2. 如果当前处于软中断执行上下文, 那么统计到 softirq 字段中// 3. 否则统计到 system 字段中if (hardirq_count() - hardirq_offset)cpustat->irq = cputime64_add(cpustat->irq, tmp);else if (softirq_count())cpustat->softirq = cputime64_add(cpustat->softirq, tmp);elsecpustat->system = cputime64_add(cpustat->system, tmp);...
}

account_system_time 函数主要分 3 种情况进行统计:

  • 如果当前处于硬中断执行上下文,那么增加到 CPU 统计结构的 irq 字段中。

  • 如果当前处于软中断执行上下文,那么增加到 CPU 统计结构的 softirq 字段中。

  • 否则增加到 CPU 统计结构的 system 字段中。

从上面代码可以看出,irq 和 softirq 统计值也算是内核代码执行时间。

3. idle 进程执行时间统计

当系统中没有可运行的进程时,将会执行 idle 进程。也就是说,当系统执行 idle 进程时,表示系统正处于空闲状态。

idle 进程执行时间统计由 account_idle_time 函数完成,其实现如下:

void account_idle_time(cputime_t cputime)
{struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;cputime64_t cputime64 = cputime_to_cputime64(cputime);struct rq *rq = this_rq();// 分 2 种情况统计 CPU 的使用情况// 1. 如果系统有进程正在等待 I/O 操作完成, 那么将统计到 iowait 字段中// 2. 否则将统计到 idle 字段中if (atomic_read(&rq->nr_iowait) > 0)cpustat->iowait = cputime64_add(cpustat->iowait, cputime64);elsecpustat->idle = cputime64_add(cpustat->idle, cputime64);
}

account_idle_time 函数也分两种情况进行统计:

  • 如果系统中有正在等待 I/O 操作完成的进程,那么增加到 CPU 统计结构的 iowait 字段中。

  • 否则增加到 CPU 统计结构的 idle 字段中。

从上面的分析可以看出,iowait 统计值也属于空闲时间的一种。

top 命令的 CPU 使用率

通过源码分析,我们知道 top 命令中 CPU 使用率各种类型的意思,现在我们来介绍一下 top 命令是怎么计算各种类型的 CPU 使用率。

要获取各个 CPU 的使用情况信息,可以通过读取 /proc/stat 文件获取,如下:

[vagrant@localhost ~]$ cat /proc/stat
cpu  245 10 1142 1097923 95 0 28 0 0 0
cpu0 245 10 1142 1097923 95 0 28 0 0 0
...

上面的结果显示了 CPU 的使用情况信息,第一行代表所有 CPU 的总和,而第二行开始表示每个 CPU 核心的使用情况信息。因为我的电脑只有一个核,所以只有一条数据。

下面说说这些数据的意义,从第一个数值开始分别代表:user ,nicesystemidleiowait, irqsoftirqsteal

所以,top 命令的 CPU 使用率计算公式如下:

CPU总时间 = user + nice + system + idle + wait + irq + softirq + steal
%us = user / CPU总时间
%ni = nice / CPU总时间
%sy = system / CPU总时间
%id = idel / CPU总时间
%wa = wait / CPU总时间
%hi = irq / CPU总时间
%si = softirq / CPU总时间
%st = steal / CPU总时间

嗯,看起来还是挺简单的。

总结

本文主要分析了 top 命令中的 CPU 使用率的意义和实现原理,希望通过本文,能够帮助大家对 top 命令有更深的认识。


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

嵌入式Linux

微信扫描二维码,关注我的公众号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/465898.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

哈尔特征Haar

哈尔特征(Haar-like features) 是用于物体识别的一种数字图像特征。它们因为与哈尔小波转换 极为相似而得名,是第一种即时的人脸检测運算。 历史上,直接使用图像的强度(就是图像每一个像素点的RGB值)使得特征的计算强度很大。帕帕…

乐鑫科技2022笔试面试题

来源于读者投稿,作者来源于牛客网的 galun 。投递方式:内推。岗位:嵌入式软件实习生。个人情况:本科双非电子信息工程,硕士华五软件工程研一在读;本科做过一些很水的项目 ,也拿项目搞了一些奖&a…

同事在RTOS临界区嵌套使用栽了跟头~

1裸机与RTOS的理解首先这里只针对单核CPU架构的芯片展开讨论,大部分是MCU吧,而多核CPU的讨论相对比较复杂,暂不涉及~玩RTOS的朋友都知道,裸机与OS的最大区别就是实现多任务的并发,其实你说裸机就不能实现任务的并发吗 …

一道内存分配的面试题

这是读者在知识星球上写的面试题我之前写的文章有很完整说过这部分C语言,函数不可返回指向栈内存的指针C 语言内存分配堆和栈的区别(转过无数次的文章)看完上面的文章,我觉得你至少对C语言程序变量内存有一个概念了解了。然后看下…

一道内存分配的面试题后续

昨天写的题目,在VC6.0上面测试一下一道内存分配的面试题结果发现一个问题,发现输出结果竟然没有问题,我很慌,如果这样的输出结果没有问题的话,那肯定是跟我们的理论对不上号的。所以我只能继续调试先把问题抛在printf上…

Qt学习之路(11): MainWindow

尽管Qt提供了很方便的快速开发工具QtDesigner用来拖放界面元素,但是现在我并不打算去介绍这个工具,原因之一在于我们的学习大体上是依靠手工编写代码,过早的接触设计工具并不能让我们对Qt的概念突飞猛进……前面说过,本教程很大程…

要毕业了,我应该做点啥?

这几天是高考的日子,高考结束,也意味着有很多人要离开学校,距离我毕业已经过去很多年了,现在还能记得那些无忧无虑的日子,毕竟人这一辈子,能这么肆无忌惮的时间并不多。最近因为发了几个不错的岗位招聘&…

我那个37岁的大神朋友,后续

还记得我之前写的这篇文章吗?我一个37岁的程序员朋友写这篇文章的时候,我建议我的这个朋友跳槽找更好的工作,可以换个行业,换一个更有钱的领域,做技术不能单单是做技术,需要有点眼光,比如选择行…

扒一扒中断为什么不能调printf

[导读] 大家好,我是逸珺。前面说会写一下Modbus-RTU的实现,写了1000多字了,有兴趣的稍等一下哈。前面在一个群里看到一个朋友在一个串口接收中断里打印遇到了问题,今天聊下这个话题。扒一扒printf 对于单片机中printf到底向哪里打…

躺平,躺下就能赢吗?

之前在群里讨论这个话题,说躺平挺好的,没那么大压力,我也觉得躺平是好事,每个人都要追求理想的权力,那么反过来,每个人也有不追求理想的权力。躺平如果说的好听一些,也可以认为是躺赢&#xff0…

感觉stm32太简单是一种自负吗?

其实简单或者复杂都不重要,重要的是通过STM32我们能学习到什么?做一个键盘/鼠标,可以学习USB协议。做一个联网设备,需要学习以太网,TCP/IP协议的底层实现。做一个无线设备,可能需要学习蓝牙、WIFI或者zigbe…

耗时两年,19岁小伙采用230片纯74逻辑芯片搭建出32位处理器!可玩贪吃蛇

从设计 CPU、制作原型机、最终成品到软件编程,19 岁极客小伙用了整整两年的时间。RISC-V 是一个基于精简指令集(RISC)原则的开源指令集架构(ISA),它是对应开源软件运动的一种「开源硬件」。该项目于 2010 年…

VC++ 6.0 与VS2008 C++ DEBUG工具(Windows)介绍

在VC 6.0 里面,debug工具有这些: 请看大图展示: 这里面几个工具都是经常用到的。比如:上下文信息,可以查看当前变量的值和地址Memory: 可以输入地址查看里面的内容。对调试和检查指针特别有用。 在vs2008里…

数组与指针不能混用的情况

扫描二维码获取更多精彩嵌入式杂牌军编辑|追梦星空公众号|嵌入式杂牌军✎ 编 者 悟 语正当性的出发点应该是少目的性、不带偏见、以尊重为前提的多方考虑。文 章 导 读C中的数组有能混用的情况,有不能混用的情况,今天就带小伙伴们探究一下!阅…

[CTO札记]盛大游戏上市,是对《文化产业振兴规划》的响应

重要国策《文化产业振兴规划》于9月26日正式对外公布。巧合的是,就在前一天(9月25日 ),盛大游戏(SDG)成功在NASDAQ上市,并且创下了美股IPO规模之最(10亿美元)。1&#xf…

Linux内核入门之路 (非广告)

笔者从开始接触 Linux 内核应该有 4 ~ 5 年了,虽然不敢说非常了解 Linux 内核,但起码也有了点眉目。所以,本文主要想分享一下我的 Linux 内核入门之路,如果对大家有帮助的话,希望能够转发一下,帮助更多想学…

万能红外遥控开发

下班刚回到家,天气很热~空调遥控器呢?找不到!躺平不想动~风扇遥控器呢?找不到!想看电视,不想动~电视遥控器呢?找不到!好不容易找到了,遥控器没电?崩溃&#x…

[Lydsy1805月赛] 对称数

挺不错的一道数据结构题QWQ。 一开始发现这个题如果不看数据范围的话,妥妥的树上莫队啊23333,然鹅10组数据是不可能让你舒舒服服的树上莫队卡过的23333 于是想了想,这个题的模型就是,把u到v链上的权值出现奇偶次的01串搞出来&…

linux下被遗忘的gpio_keys按键驱动

我们新项目硬件设计上使用gpio口做按键,所以我就需要搞定这个驱动,本来想自己写一个gpio口的按键驱动,然后看了下内核下面的代码,已经有现成的了。Linux内核下游很多很多的现成驱动,只要你想得到的,基本都是…

如何通过审计安全事件日志检测密码喷洒(Password Spraying)攻击

许多渗透测试人员和攻击者通常都会使用一种被称为“密码喷洒(Password Spraying)”的技术来进行测试和攻击。对密码进行喷洒式的攻击,这个叫法很形象,因为它属于自动化密码猜测的一种。这种针对所有用户的自动密码猜测通常是为了避…