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;
	else
		index = 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;
	else
		cpustat[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 的情况

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯算法双周赛

四、赛后真题解析 比赛赛后将提供免费直播讲解,主讲人:待定。时间:07 月 13 日(比赛当日)晚 21 时。观看直播地址:第3场蓝桥算法季度赛赛后题解直播 - 蓝桥云课 - 哔哩哔哩直播,二次元弹幕直播…

ShareSDK HarmonyOS NEXT集成指南

集成前准备 注册账号 使用MobSDK之前,需要先在MobTech官网注册开发者账号,并获取MobTech提供的AppKey和AppSecret,详情可以点击查看注册流程 ShareSDK流程图 集成配置 添加依赖 在Terminal窗口中,执行如下命令进行安装 ohpm …

彻底搞懂Webpack插件

前言 首先我们先回忆一下Webpack插件是如何使用的?下面是一份基础的Webpack配置文件: let htmlWebpackPlugin require(html-webpack-plugin);module.exports {mode: development,entry: {main: path.join(__dirname, src/index.js)},output: {path: …

认识软件测试

认识软件测试 软件测试能力要求一、软件测试的步骤1.需求2.测试点3.测试用例4.执行测试用例5.缺陷管理6.测试报告 一、测试用例(test case)**用例编写要素**: 测试用例设计方法1.等价类2.边界值3.判定表法4.场景法 软件测试能力要求 软件测试…

张颂文百花提名,男配界笑出“颂”彩

在这个星光熠熠的百花奖舞台上, 张颂文老师犹如一坛陈年老酒,越品越有味, 竟不声不响地提名了最佳男配角!这下可好, 男配界仿佛一夜之间被“颂”风吹得花枝乱颤,笑料百出。你说张颂文老师这演技&#xf…

嵌套组合请求对象的校验与全局捕捉

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119qq.com] &#x1f4f1…

怎么压缩图片大小?6种无需牺牲质量的图片压缩方法

经常处理图片的小伙伴都知道,高质量的图片往往会占据电脑大量的存储空间,导致图片传输及存储的不便。因此,掌握如何压缩图片大小变得尤为重要。本文将详细介绍图片压缩的几种方法,帮助你高效地减小图片文件大小,让你的…

【ACM出版,马来西亚-吉隆坡举行】第四届互联网技术与教育信息化国际会议 (ITEI 2024)

作为全球科技创新大趋势的引领者,中国不断营造更加开放的科技创新环境,不断提升学术合作的深度和广度,构建惠及各方的创新共同体。这是对全球化的新贡献,是构建人类命运共同体的新贡献。 第四届互联网技术与教育信息化国际学术会议…

秒懂设计模式--学习笔记(5)【创建篇-抽象工厂】

目录 4、抽象工厂4.1 介绍4.2 品牌与系列(针对工厂泛滥)(**分类**)4.3 产品规划(**数据模型**)4.4 生产线规划(**工厂类**)4.5 分而治之4.6 抽象工厂模式的各角色定义如下4.7 基于此抽象工厂模式以品牌与系…

本地文本向量模型的部署提供兼容openai的接口

前言 之前部署了fastgpt官方文档的一个,提供的一个m3e-large的向量模型打包的docker镜像,虽然使用起来整体效果还可以,但是有些文本向量相似度匹配的结果还是不太满意的,目前,网络上层出不穷的带推理文本向量,想体验一下,于是我基于modelscope库封装了一个兼容open ai的…

有哪些Python书籍是程序员强烈推荐?

有一本升级版的经典Python项目编程书一定要推荐一下。 Python极客项目编程(第2版) 第一版累计销售19万册,豆瓣评分8.4。每个项目都按照【讲解原理-分析需求-代码精讲-知识小结-扩展练习-完整代码】的方式进行讲解,并提供可下载运…

【文档+源码+调试讲解】科研经费管理系统

目 录 目 录 摘 要 ABSTRACT 1 绪论 1.1 课题背景 1.2 研究现状 1.3 研究内容 2 系统开发环境 2.1 vue技术 2.2 JAVA技术 2.3 MYSQL数据库 2.4 B/S结构 2.5 SSM框架技术 3 系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2 操作可行性 3.1.3 经济可行性 3.1…

实习总结 --- 内部平台使用

常用术语 CR CR–标准问题分类管理平台:由业务类型-角色-国家-品类-Page定义。 FAQSOP FAQ是端上用户自助的第一道关口,在引导用户进行自助解决上起关键作用 SOP是指标准作业程序,客服SOP是针对用户遇到的具体问题场景,给客服…

论文阅读【时间序列】DSformer

论文阅读【时间序列】DSformer arxive: DSformer: A Double Sampling Transformer for Multivariate Time Series Long-term Prediction github: MTST 分类:多变量时间序列(Multivariate time series) 核心观点 多变量时间序列3个维度信息 …

从零开始实现大语言模型(一):概述

1. 前言 大家好,我是何睿智。我现在在做大语言模型相关工作,我用业余时间写一个专栏,给大家讲讲如何从零开始实现大语言模型。 从零开始实现大语言模型是了解其原理及领域大语言模型实现路径的最好方法,没有之一。已有研究证明&…

ArcGIS中将测绘数据投影坐标(平面坐标)转地理坐标(球面经纬度坐标)

目录 前言1.测绘数据预览1.1 确定带号1.2 为什么是对Y轴分带,而不是对X轴分带? 2 测绘数据转shp2.1 添加数据2.2 显示XY数据2.3 添加经纬度字段2.4 计算经纬度 3.shp数据重投影4.总结 前言 最近在刚好在做一个小功能,将测绘数据转为经纬度坐标…

一些硬件知识(十二)

X电容是接在火线和零线之间,Y电容是接在火零线和地之间。X电容滤除差模干扰,Y电容滤除共模干扰: 高频干扰信号经过X电容后幅度没有变化,相位相差180度: DW01电池管理芯片: M1、M2:这两个为N沟道…

BMA530 运动传感器

型号简介 BMA530是博世(bosch-sensortec)的一款运动传感器。时尚简约的可穿戴设备为功能强大的组件提供了很小的空间。具有先进功能集的下一代加速度计是世界上最小的加速度传感器(1.2 x 0.8 x 0.55 mm)。它专为紧凑型设备而设计&…

本地项目推送到gitlab仓库的保姆级教程

目录 1、安装git (1)Windows系统 (2)Linux系统 2、gitlab创建空白项目 3、创建密钥 4、将密钥添加到gitlab中 5、远程配置 (1)配置全局的用户和邮箱 (2)本地文件夹初始化 …

【代码随想录】【算法训练营】【第52天】 [647]回文子串 [516]最长回文子序列

前言 思路及算法思维,指路 代码随想录。 题目来自 LeetCode。 day 52,周五,开始补作业了~ 题目详情 [647] 回文子串 题目描述 647 回文子串 解题思路 前提:寻找回文子串,子串意味着元素连续 思路:…