linux的Top学习

学习文档

https://www.cnblogs.com/liulianzhen99/articles/17638178.html

TOP

问题 1:top 输出的利用率信息是如何计算出来的,它精确吗?
在这里插入图片描述

  • top 命令访问 /proc/stat 获取各项 cpu 利用率使用值
  • 内核调用 stat_open 函数来处理对 /proc/stat 的访问
  • 内核访问的数据来源于 kernel_cpustat 数组,并汇总
  • 打印输出给用户态

strace 跟踪 top 命令的系统调用

# strace top
...
openat(AT_FDCWD, "/proc/stat", O_RDONLY) = 4
openat(AT_FDCWD, "/proc/2351514/stat", O_RDONLY) = 8
openat(AT_FDCWD, "/proc/2393539/stat", O_RDONLY) = 8
...

除了 /proc/stat 外,还有各个进程细分的 /proc/{pid}/stat,是用来计算各个进程的 cpu 利用率时使用。

proc/stat伪文件

内核为各个伪文件都定义了处理函数,/proc/stat 文件的处理方法是 proc_stat_operations

//file:fs/proc/stat.c
static int __init proc_stat_init(void)
{proc_create("stat", 0, NULL, &proc_stat_operations);return 0;
}static const struct file_operations proc_stat_operations = {.open  = stat_open,...
};

proc_stat_operations 中包含了操作该文件时对应的操作方法,当打开 /proc/stat 文件时,stat_open 就会被调用
stat_open 依次调用 single_open_size->show_stat 来输出数据内容:

//file:fs/proc/stat.c
static int show_stat(struct seq_file *p, void *v)
{u64 user, nice, system, idle, iowait, irq, softirq, steal;for_each_possible_cpu(i) {struct kernel_cpustat *kcs = &kcpustat_cpu(i);user += kcs->cpustat[CPUTIME_USER];nice += kcs->cpustat[CPUTIME_NICE];system += kcs->cpustat[CPUTIME_SYSTEM];idle += get_idle_time(kcs, i);iowait += get_iowait_time(kcs, i);irq += kcs->cpustat[CPUTIME_IRQ];softirq += kcs->cpustat[CPUTIME_SOFTIRQ];...}//转换成节拍数并打印出来seq_put_decimal_ull(p, "cpu  ", nsec_to_clock_t(user));seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));...
}

for_each_possible_cpu 是在遍历存储着 cpu 使用率数据的 kcpustat_cpu 变量
该变量是一个 percpu 变量,它为每一个逻辑核都准备了一个数组元素
里面存储着当前核所对应各种事件,包括 user、nice、system、idel、iowait、irq、softirq 等
在这里插入图片描述
在这个循环中,将每一个核的每种使用率都加起来,最后通过 seq_put_decimal_ull 将这些数据输出

注意
在内核中实际每个时间记录的是纳秒数,但是在输出时统一转化成节拍单位
/proc/stat 的输出是从 kernel_cpustat 这个 percpu 变量中读取出来

统计数据怎么来的

内核是以采样的方式来统计 cpu 使用率,这个采样周期依赖的是 Linux 时间子系统中的定时器:
在这里插入图片描述
Linux 内核每隔固定周期会发出 timer interrupt (IRQ 0),这有点像乐谱中的节拍。
每隔一段时间,就打出一个拍子,Linux 响应并处理一些事情。

一个节拍的长度是多长时间,是通过 CONFIG_HZ 来定义。它定义的方式是每一秒有几次 timer interrupts。
不同的系统中这个节拍的大小可能不同,通常在 1 ms 到 10 ms 之间。
每次当时间中断到来时,调用 update_process_times 来更新系统时间,更新后的时间存储在 percpu 变量 kcpustat_cpu 中。
在这里插入图片描述
问题 2:ni 这一列是 nice,它输出的是 cpu 在处理啥时的开销?

问题 3:wa 代表的是 io wait,那么这段时间中 cpu 到底是忙碌还是空闲?

CPU的idle和iowait的区别

idle 状态:
表示 CPU 处于空闲状态,即没有任何任务正在被执行
这意味着 CPU 此时没有工作可做,可以随时接受新的任务分配
例如,当系统处于待机状态,用户没有进行操作,且后台也没有运行任务时,CPU 可能处于 idle 状态

iowait 状态:
指 CPU 等待 I/O 操作完成所花费的时间
当系统正在进行磁盘读写、网络通信等 I/O 操作时,如果这些操作还未完成,CPU 就会处于 iowait 状态
比如,当从硬盘读取大量数据或者向网络发送大量数据时,可能会导致 CPU 进入 iowait 状态

总结:
idle 是 CPU 真正的空闲,没有任务需要处理
iowait 是 CPU 因为等待 I/O 操作而暂时无法执行计算任务

过高的 idle 可能表示系统资源未被充分利用
过高的 iowait 可能暗示 I/O 子系统存在性能瓶颈,需要优化 I/O 设备或相关的操作流程
如果一个数据库服务器经常出现高 iowait,可能需要考虑升级存储设备、优化数据库的读写操作、增加缓存,来减少 I/O 操作次数

update_process_times 简介

普通定时器: arch_timer_handler_phys->tick_handle_periodic->update_process_times
高精度定时器: tick_sched_handle->update_process_times

linux 进程可以同时执行,是因为采用时间片轮转方案。
在这里插入图片描述
每个进程都会分得相应的时间片,当前进程时间片用完,CPU就会停止执行当前进程,选择其他合适进程。

什么时候判断当前进程的时间片是否用完?
依赖于系统timer,timer周期性产生时钟中断,在中断处理函数中,会更新当前进程时间等统计信息
并判断当前进程的时间片是否用完,是否需要切换到其他进程执行。
这个工作由update_process_times函数来实现。

(引入采用周期的概念,定时每 1 毫秒采样一次。如果采样的瞬时,cpu 在运行,就将这 1 ms 记录为使用,这时会得出一个瞬时的 cpu 使用率,把它都存起来。当统计 3 秒内的 cpu 使用率时,比如 t1 ~ t2 这段时间范围。那就把这段时间内所有瞬时值全加,取个平均值,统计相对准确,避免瞬时值剧烈震荡且粒度过粗问题了)
在这里插入图片描述
update_process_times函数不会做实际的进程切换动作,只会设置是否需要做进程切换的标记,真正的切换在schedule函数中实现。

linux每个时钟中断(又称tick中断)处理中都会更新进程时间,即update_process_times。

void update_process_times(int user_tick)
{struct task_struct *p=current;/* 找到多核中的cpu id */int cpu = smp_processor_id();/* // user_tick 根据 cpu 模式判断是用户态还是内核态// // linux统计时间的方式:// 1 基于整个cpu的统计// user_tick 表示 cpu 在用户态、内核态、中断状态// 此处把一个 tick 的时间累加到 kstat_cpu(i).cpustat.xx// /proc/stat的统计值是在此处统计的// 表示cpu在用户态、内核态中断中各占用多少时间// 对应 stat.c(fs/proc):static int __init proc_stat_init(void)// // 2 基于进程的统计// linux还有一种统计时间的方法更细化// 统计的是调度实体上的时间 sum_exec_runtime// 它在 sched_clock_cpu 函数中基于 timer 计算// /proc/pid/stat、/proc/pid/task/tid/stat 中的时间是在此处统计// 它统计了一个进程/线程占用 cpu 的时间,对应 do_task_stat 实现*/account_process_tick(p, user_tick);/*// 此处负责系统中的定时器到期操作,并未真正处理,只是实现 raise_softirq(TIMER_SOFTIRQ)// 当这个 tick 中断退出 irq_exit 时,会处理 TIMER_SOFTIRQ 软中断// TIMER_SOFTIRQ 软中断处理函数 run_timer_softirq() 负责处理到期的定时器*/run_locl_timers();/* 与进程和调度用过的时间参数 */scheduler_tick();
}

根据 Tick 产生是在用户态/内核态,以及idle进程的上下文等信息,选择不同函数进行处理
这里是把 TICK_NSEC ,也就是每 Tick 对应的 ns 加到对应的 cpustat 数组中
即 cpustat 数组中的数据,虽然是 ns 级,但精度是按照 Tick 的频率而定,不算准确

//file:kernel/sched/cputime.c
void account_process_tick(struct task_struct *p, int user_tick)
{cputime = TICK_NSEC;...if (user_tick)//3.1 统计用户态时间account_user_time(p, cputime);else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET))//3.2 统计内核态时间account_system_time(p, HARDIRQ_OFFSET, cputime);else//3.3 统计空闲时间account_idle_time(cputime);
}

首先设置 cputime = TICK_NSEC
一个 TICK_NSEC 的定义是一个节拍所占的纳秒数。
接下来根据判断结果分别执行 account_user_time、account_system_time 和 account_idle_time 来统计用户态、内核态和空闲时间

用户态时间统计

//file:kernel/sched/cputime.c
void account_user_time(struct task_struct *p, u64 cputime)
{//分两种种情况统计用户态 CPU 的使用情况int index;index = (task_nice(p) > 0) ? CPUTIME_NICE : CPUTIME_USER;//将时间累积到 /proc/stat 中task_group_account_field(p, index, cputime);......
}

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

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

其实用户态的时间不只是 user 字段,nice 也是
之所以要把 nice 分出来,是为了让 Linux 用户更一目了然地看到调过 nice 的进程所占的 cpu 周期有多少
如果想要观察系统的用户态消耗的时间,应将 top 中输出的 user + nice ,不是只看 user

接着调用 task_group_account_field 来把时间加到前面提到的 kernel_cpustat 内核变量中。

//file:kernel/sched/cputime.c
static inline void task_group_account_field(struct task_struct *p, int index, u64 tmp)
{__this_cpu_add(kernel_cpustat.cpustat[index], tmp);...
}

内核态时间统计

//file:kernel/sched/cputime.c
void account_system_time(struct task_struct *p, int hardirq_offset, u64 cputime)
{if (hardirq_count() - hardirq_offset)index = CPUTIME_IRQ;else if (in_serving_softirq())index = CPUTIME_SOFTIRQ;elseindex = CPUTIME_SYSTEM;account_system_index_time(p, cputime, index);
}

内核态的时间主要分 3 种情况进行统计

  • 如果当前处于硬中断执行上下文,那么统计到 irq 字段中
  • 如果当前处于软中断执行上下文,那么统计到 softirq 字段中
  • 否则统计到 system 字段中

判断好要加到哪个统计项中后,依次调用 account_system_index_time、task_group_account_field
来将这段时间加到内核变量 kernel_cpustat 中

空闲时间的累积

在内核变量 kernel_cpustat 中不仅仅是统计了各种用户态、内核态的使用统计,空闲也一并统计起来。
如果在采样的瞬间,cpu 既不在内核态也不在用户态的话,就将当前节拍的时间都累加到 idle 中。

//file:kernel/sched/cputime.c
void account_idle_time(u64 cputime)
{u64 *cpustat = kcpustat_this_cpu->cpustat;struct rq *rq = this_rq();if (atomic_read(&rq->nr_iowait) > 0)cpustat[CPUTIME_IOWAIT] += cputime;elsecpustat[CPUTIME_IDLE] += cputime;
}

在 cpu 空闲的情况下,进一步判断当前是不是在等待 IO(例如磁盘 IO):

  • 是的话,这段空闲时间会加到 iowait 中
  • 否则,加到 idle 中

iowait 其实是 cpu 的空闲时间,只不过是在等待 IO 完成而已
io wait 其实是 cpu 在空闲状态的一项统计,只不过这种状态和 idle 的区别是 cpu 是因为等待 io 而空闲

总结

实际查看一下服务器的 cpu 利用率的demo
https://github.com/yanfeizhang/coder-kung-fu/blob/main/tests/cpu/test06/cpu_stat.sh

在这里插入图片描述

TOP 中输出的 cpu 时间项目其实大致可以分为三类:
第一类:用户态消耗时间,包括 user 和 nice;如果想看用户态的消耗,要将 user 和 nice 加起来
第二类:内核态消耗时间,包括 irq、softirq 和 system
第三类:空闲时间,包括 io_wait 和 idle;其中 io_wait 也是 cpu 的空闲状态,只不过是在等 io 完成而已;如果只是想看 cpu 到底有多闲,应该把 io_wait 和 idle 加起来。

其他

当前程序使用的堆栈一个是内核堆栈,一个是用户态堆栈
普通的内核态可以视为是系统调用进入
是否在 hardirq 环境以及 softirq 环境,可以通过 preempt_count(thread_info 的一个成员)进行判断
idle状态,只需要判断当前进程是否是idle进程就可以
iowait :在 idle 进程上下文,但 rq->nr_iowait 仍大于 0 的情况

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

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

相关文章

AcWing 1256:扩展二叉树

【题目来源】https://www.acwing.com/problem/content/1258/【题目描述】 由于先序、中序和后序序列中的任一个都不能唯一确定一棵二叉树,所以对二叉树做如下处理,将二叉树的空结点用 补齐,如图所示。 我们把这样处理后的二叉树称为原二叉树…

零知识证明技术:隐私保护的利器

在当今信息时代,数据安全和隐私保护的重要性日益凸显。随着技术的发展,密码学在保障信息安全方面发挥着越来越重要的作用。其中,零知识证明技术作为一种新兴的密码学方法,为隐私保护提供了强有力的支持。本文将简要介绍零知识证明…

3.js - premultiplyAlpha

你瞅啥啊!!! 先看效果图吧 代码 // ts-nocheck // 引入three.js import * as THREE from three // 导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls // 导入lil.gui import { GUI } from three/ex…

pycharm中新建的临时python文件存放在哪里?

在pycharm中建立的临时python文件,从哪里可以找到呢? 1.我们打开cmd窗口,进入根目录,用dos命令“dir scratch*.py/a/s”进行查找,发现这些临时文件存放在Roaming\JetBrains\PyCharmCE2022.2\scratches 的目录里面 2.…

我全都要,全网聚合神器!绝了!

哈喽,各位小伙伴们好,我是给大家带来各类黑科技与前沿资讯的小武。 现在有不少开发者都会以“壳源”的方式(如TVBox、阅读APP等),为用户提供了更为灵活性的选择。 而今天给大家安利的是一款“壳源”的聚合神器&#…

Profibus DP主站转Modbus网关连接智能化电表通讯

Profibus DP主站转Modbus网关(XD-MDPBM20),是实现不同工业通信协议之间互联互通的设备,主要将Profibus DP协议转换为Modbus协议,实现数据的双向传输。通过Profibus DP主站转Modbus网关(XD-MDPBM20&#xff…

记一次阿里云服务器java应用无法响应且无法远程连接的问题排查

问题表现 java服务无响应,无法远程链接到服务器。 今天中午12点多,应用直接崩溃。后续进入到服务器,发现java进程都不在了, 排查过程 先安装atop工具 安装、配置并使用atop监控工具 等下次再出现时看相关时间点日志&#xff…

编译原理3-自底向上的语法分析

自底向上分析 ,就是自左至右扫描输入串,自底向上进 行分析;通过反复查找当前句型的 句柄, 并使 用产生式规则 将找到的句柄归约为相应的非终结符 。逐步进行“ 归约 ”,直到至文法的开始符号; 对于规范推导…

现代工作场所中的睡岗检测算法应用

在现代职场环境中,员工的工作状态直接影响到公司的整体效益。睡岗现象,即员工在工作时间内打瞌睡或睡觉,不仅降低了生产力,还可能带来安全隐患。因此,如何有效地检测和预防睡岗行为成为了企业管理中的一个重要课题。随…

试用笔记之-免费的汇通总账财务软件

首先下载免费汇通总账财务软件 http://www.htsoft.com.cn/download/htcaiwu.rar

不改代码,实现web.config或app.config的连接字符串加密解密

目的:加密字符串,防止明文显示。 好处:不用修改代码,微软自带功能,自动解密。 web.config 参考相关文章: Walkthrough: Encrypting Configuration Information Using Protected Configuration | Microso…

用MySQL+node+vue做一个学生信息管理系统(四):制作增加、删除、修改的组件和对应的路由

1.下载依赖: npm install vue-router 在src目录下新建一个文件夹router,在router文件夹下新建一个文件router.js文件,在component目录下新建增加删除和修改的组件,引入router.js当中 此时的init组件为主页面((二、三&…

某Dota/IM对战平台玩家助手、查看战绩下、胜率等

功能说明 WAR3游戏启动后,可以自动获取游戏双方的玩家列表,然后查询显示玩家的战绩及个人信息。附带查看玩家的战绩详情、最近游戏,查看对手及友方的战绩详情,据此推算出是否开黑、是否小号等信息 使用方法及运行效果 启动 查…

更好的方法_交叉观察器API

交叉观察器(Intersection Observer)API 是一个强大的工具,可以用来检测元素是否进入视口或从视口移出。我们可以利用这个 API 来实现粘贴式导航(也称为粘性导航),即在用户滚动页面时,导航栏会在…

TFD那智机器人仿真离线程序文本转换为现场机器人程序

TFD式样那智机器人离线程序通过Process Simulation、DELMIA等仿真软件为载体给机器人出离线,下载下来的文本程序,现场机器人一般是无法导入及识别出来的。那么就需要TFD on Desk TFD控制器来进行转换,才能导入现场机器人读取程序。 导入的文…

MySQL4(事务、函数、慢查询和索引)

目录 一、MySQL事务 1. 概念 2. 事务的ACID原则 3. MySQL实现事务的方法 4. MySQL实现事务的步骤 5. 事务的原子性、一致性、持久性 6. 事务的隔离性 7. MySql中的锁 1. 共享锁 2. 排他锁 3. 行级锁 4. 表级锁 5. 间隙锁 6. 临键锁 7. 记录锁 8. 意向共享锁…

Python - 递归函数(Recursive Function)的速度优化 (Python实现)

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/140137432 免责声明:本文来源于个人知识与开源资料,仅用于学术交流,不包含任何商业技术,欢迎相互学…

余承东在母校西工大毕业典礼演讲:定位决定地位,眼界决定境界。

添加图片注释,不超过 140 字(可选) 【6月29日,西北工业大学2024届本科生毕业典礼暨学位授予仪式隆重举行。典礼上,华为常务董事、终端BG 董事长、智能汽车解决方案BU 董事长余承东作为校友代表致辞,为毕业生…

Linux_fileio实现copy文件

参考韦东山老师教程&#xff1a;https://www.bilibili.com/video/BV1kk4y117Tu?p12 目录 1. 通过read方式copy文件2. 通过mmap映射方式copy文件 1. 通过read方式copy文件 copy文件代码&#xff1a; #include <sys/types.h> #include <sys/stat.h> #include <…

Python知识点背诵手册,超详细知识梳理

一、手册介绍 《Python知识点背诵手册》是一份详尽的Python学习资料&#xff0c;旨在帮助学习者系统地掌握Python语言的基础知识和进阶技能。该手册将Python的所有关键语法和概念进行了精炼的总结&#xff0c;并以易于理解和记忆的方式呈现。以下是手册的主要特点和内容概述&a…