linux的Top学习

news2024/11/19 8:33:53

学习文档

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 的情况

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

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

相关文章

PMP通过率为什么高?

很多人在初步了解PMP的时候,都会考虑到PMP考试的难度以及通过率,继而在网上查询到很多资料后,都会发现,其实PMP的国内通过率一直都是很高的。 通过率高≠含金量低 看到PMP的通过率这么高,很多人觉得证书的水分很大&a…

鼠标连点器:解放双手的自动化效率神器,鼠标自动快速连点!

日常使用电脑整理工作时,总会做一些重复的工作,比如:刷题、做任务、浏览多张图片、浏览多个文件等。这些操作的工作量在于鼠标左键,需要一直重复的点,略微有些枯燥了。 面对重复且枯燥的工作,我们可以借助第…

Windows系统安装NVM,实现Node.js多版本管理

目录 一、前言 二、NVM简介 三、准备工作 1、卸载Node 2、创建文件夹 四、下载NVM 五、安装NVM 六、使用NVM 1、NVM常用操作命令 2、查看NVM版本信息 3、查看Node.js版本列表; 4、下载指定版本Node.js 5、使用指定版本Node.js 6、查看已安装Node.js列…

快速入门FreeRTOS心得(正点原子学习版)

对于FreeROTS,我第一反应想到的就是通信里的TDM(时分多址)。不同任务给予分配不同的时间间隔,也就是任务之间在每个timeslot都在来回切换。 这里有重要的一点,就是中断要短小,优先级是自高到底进行打断。 …

如何避免删库跑路?

如何避免删库跑路,这几乎是一个老生常谈的话题,也是大部分上了规模的企业都很关心的话题,京东到家、微盟、链家、思科... 在这些大企业上发生过的删库事件仍然历历在目,无论是否当事人有意为之还是系统 BUG 导致,造成的…

vue-advanced-chat 聊天控件的使用

测试代码:https://github.com/robinfoxnan/vue-advanced-chat-test0 控件源码:https://github.com/advanced-chat/vue-advanced-chat 先上个效果图: 这个控件就是专门为聊天而设计的,但是也有一些不足: 1&#xf…

国际数字影像产业园:汇聚全球力量,共绘影像新蓝图

在数字化浪潮席卷全球的今天,我们自豪地宣布,国际数字影像产业园已正式起航,以全球视野为引领,致力于推动数字影像产业的创新发展,引领全球潮流。 一、汇聚全球智慧 国际数字影像产业园以开放包容的姿态,汇…

MIX OTP——使用 ETS 加速

每次我们需要查找存储容器时,我们都需要向注册表发送一条消息。如果我们的注册表被多个进程同时访问,注册表可能会成为瓶颈! 在本章中,我们将了解 ETS(Erlang Term Storage)以及如何将其用作缓存机制。 警…

【信息系统项目管理师】常见图表

作文里面的画图题用语言描述画图过程 合同 采购综合评分标准 责任分配矩阵 成本预算表 成本估算 成本管理计划 活动清单 活动属性 变更日志 问题日志 项目章程 自己再添加更多内容 甘特图 甘特图包含以下三个含义: 1、以图形或表格的形式显示活动; 2、…

JavaScript中window对象 , location对象以及history对象使用方法详细介绍

2.BOM(Browser Object Model) 操作浏览器的。常用的浏览器对象: 1.window对象:Window 对象表示浏览器中打开的窗口。 2.location对象:Location 对象包含有关当前 URL 的信息。Location 对象是 window 对象的一部分&…

[PyTorch]:加速Pytorch 模型训练的几种方法(几行代码),最快提升八倍(附实验记录)

本篇文章转自:Some Techniques To Make Your PyTorch Models Train (Much) Faster 本篇博文概述了在不影响 PyTorch 模型准确性的情况下提高其训练性能的技术。为此,将 PyTorch 模型包装在 LightningModule 中,并使用 Trainer 类来实现各种训…

使用 Python 五年后,我发现学 python 必看这三本书!少走一半弯路

第一本 《Python编程-从入门到实践》 适合零基础的读者 豆瓣评分:9.1 推荐指数:5颗星 推荐理由: 本书是针对所有层次的 Python 读者而作的 Python 入门书。全书分为两部分: 第一部分介绍使用Python 编程所必须了解的…

将excel表格转换为element table(上)

最近有个功能需要将excel展示到html 界面里面,看是简单的一个需求也是需要费尽心思才完得成 原始数据 想要把excel 读取出来,于是使用xlsl的插件 npm i xlsx通过插件可以获取到已经分析好的数据 然后使用sheet_to_html将数据转换为html 再使用v-htm…

ROS2 RQT

1. RQT是什么 RQT是一个GUI框架,通过插件的方式实现了各种各样的界面工具。 强行解读下:RQT就像插座,任何电器只要符合插座的型号就可以插上去工作。 2.选择插件 这里我们可以选择现有的几个RQT插件来试一试,可以看到和话题、参…

视频太大怎么压缩变小?6款视频压缩软件免费版分享

视频太大怎么压缩得又小又清晰呢?无论是视频文件传输、视频文件存储,还是进行自媒体视频上传,都对视频文件的大小有一定的限制。高质量的视频文件往往伴随着文件占据大量存储空间,导致文件传输速度变慢。今天教大家6种视频压缩软件…

配置WLAN 示例

规格 仅AR129CVW、AR129CGVW-L、AR109W、AR109GW-L、AR161W、AR161EW、AR161FGW-L、AR161FW、AR169FVW、AR169JFVW-4B4S、AR169JFVW-2S、AR169EGW-L、AR169EW、AR169FGW-L、AR169W-P-M9、AR1220EVW和AR301W支持WLAN-FAT AP功能。 组网需求 如图1所示,企业使用WLAN…

搜维尔科技:数据手套为什么要选择SenseGlove

了解 SenseGlove SenseGlove 是一支由电子工程师、触觉研究人员和计算机视觉专家、XR 开发人员、UX 设计师和产品创新者组成的科幻爱好者团队,他们拥有丰富人类能力和赋予 Metaverse 意义的技能和热情。 推进触觉技术是我们实现这一目标的方式。 公司及产品背景 S…

将多个SQL查询合并的两种方式

说明:单个简单查询是非常容易的,但是为了避免多次访问访问数据库,我们会尽可能通过表关联将业务所需要的字段值一次性查出来。而有时候不太清楚表之间的关联关系(这取决于对业务的熟悉程度),或者实际情况就…

ubuntu 安装并启用 samba

环境:ubuntu server 24.04 步骤如下: sudo apt update sudo apt install samba修改配置文件: sudo vi /etc/samba/smb.conf新增内容: [username]path /home/[username]available yesvalid users [username]read only nobrow…

2021强网杯

一、环境 网上自己找 二、步骤 2.1抛出引题 在这个代码中我们反序列&#xff0c;再序列化 <?php$raw O:1:"A":1:{s:1:"a";s:1:"b";};echo serialize(unserialize($raw));//O:1:"A":1:{s:1:"a";s:1:"b";…