进程管理实践:load_monitor负载监控模块(笔记)

news/2024/10/18 9:20:15/

为了更深入的理解PCB结构体task_struct,通过一个案例来进行

实现一个可应用于工程实践中的负载分析方法,load_monitor负载监视模块

系统负载

通过top或者uptime这样的命令来查看系统的负载
会分别动态和静态的显示出系统的负载情况,其中load average字段分别表示系统1,5,10分钟的负载情况。
wa表示iowait

负载和CPU核心数

  • 单核CPU,就是单个处理单元,任务串行工作,相当于进程在一条车道上通行。
  • 多核CPU,就是一个物理CPU有多个单独的核进行工作,任务可以并行工作,相当于进程可以在多条车道上通行。
  • 多CPU,就是一个计算机系统中集成了多个物理CPU。

通过nproc或者lscpu命令可以查看CPU的核心数。

负载就是指CPU的负载情况,以负载值0.5,1,1.7和2.3举例
在单核的环境下,0.5表示负载良好,1表示负载正好满了,1.7表示还有0.7的进程在等待,2.3表示还有1.3的进程在等待
在2核的环境下,0.5,1,1.7都表示负载良好。2.3表示负载满了,但依然有0.3的进程在等待。

需求分析

该模块的功能是持续的监视系统的负载,当系统负载超过某一阈值时,打印出系统内所有线程的调用栈。
通过调用栈的信息,进一步分析负载异常。

为了实现这样的功能,内核模块需要完成3项工作

  1. 获得系统负载值
  2. 定时判断当前系统负载值是否超过某一阈值
  3. 打印线程的调用栈

代码实例

#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>#include<linux/kallsyms.h>
#include<linux/sched.h>
#include<linux/hrtimer.h>
#include<linux/stacktrace.h>#define FSHIFT 11
#define FIXED_1 (1 << FSHIFT)
#define LOAD_INT(x) ((x) >> FSHIFT) // 高位整数
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1 - 1)) * 100)
#define BACKTRACE_DEPTH 20 // 保存的栈深struct hrtimer timer; // 高精度定时器
static unsigned long *ptr_avenrun; // 系统负载保存的地址static void print_all_task_stack(void){struct task_struct *g, *p;unsigned long backtrace[BACKTRACE_DEPTH]; // 每个调用具体的信息struct stack_trace trace; // 保存进程调用栈信息memset(&trace, 0, sizeof(trace));memset(backtrace, 0, BACKTRACE_DEPTH * sizeof(unsigned long));trace.max_entries = BACKTRACE_DEPTH; // 初始化 保存 栈深trace.entries = backtrace; // 定义保存信息数组printk("======================================\n");printk("\tLoad: %lu.%02lu, %lu.%02lu, %lu.%02lu\n",LOAD_INT(ptr_avenrun[0]), LOAD_INT(ptr_avenrun[0]),LOAD_INT(ptr_avenrun[1]), LOAD_INT(ptr_avenrun[1]),LOAD_INT(ptr_avenrun[2]), LOAD_INT(ptr_avenrun[2]));printk("dump all task: ...\n");// 接下来就是打印线程链表了, 需要先锁一下链表, 防止出现并发问题rcu_read_lock();printk("dump running task.\n");do_each_thread(g, p){if(p->state == TASK_RUNNING){ // 打印正在运行的进程printk("running task, comm: %s, pid %d\n", p->comm, p->pid);memset(&trace, 0, sizeof(trace));memset(backtrace, 0, BACKTRACE_DEPTH * sizeof(unsigned long));trace.max_entries = BACKTRACE_DEPTH;trace.entries = backtrace;save_stack_trace_tsk(p, &trace);print_stack_trace(&trace, 0);}}while_each_thread(g, p);printk("dump uninterrupted task.\n");do_each_thread(g, p){if(p->state & TASK_UNMAPPED_BASE){ // 打印不可中断的进程printk("running task, comm: %s, pid %d\n", p->comm, p->pid);memset(&trace, 0, sizeof(trace));memset(backtrace, 0, BACKTRACE_DEPTH * sizeof(unsigned long));trace.max_entries = BACKTRACE_DEPTH;trace.entries = backtrace;save_stack_trace_tsk(p, &trace);print_stack_trace(&trace, 0);}}while_each_thread(g, p);rcu_read_unlock();
}
static void check_load(void){static ktime_t last;__u64 ms;int load = LOAD_INT(ptr_avenrun[0]);if(load < 3) return ; // 判断阈值ms = ktime_to_ms(ktime_sub(ktime_get(), last));if(ms < 20 * 1000) return ; // 判断时间间隔last = ktime_get();print_all_task_stack(); // 打印所有线程栈
}
static enum hrtimer_restart monitor_handler(struct hrtimer *hrtimer){// 定时器是否需要重启enum hrtimer_restart ret = HRTIMER_RESTART;// 检查系统负载check_load();// 定时器到期时间推迟10mshrtimer_forward_now(hrtimer, ms_to_ktime(10));// 返回定时器重启信号return ret;
}
static void start_timer(void){// 初始化定时器hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_PINNED);// 指定回调函数timer.function = monitor_handler(); // 指定定时器重启的到期时间(10ms)hrtimer_start_range_ns(&timer, ms_to_ktime(10), 0, HRTIMER_MODE_REL_PINNED);
}static int load_monitor_init(void){printk("load-monitor loaded in kernel...\n");// 获得保存系统负载变量 所在的地址, 之后所有判断都会先读取一下系统负载ptr_avenrun = (void *)kallsyms_lookup_name("averrun");i(!ptr_avenrun) return -EINVAL;start_timer();return 0;
}
static void load_monitor_exit(void){printk("load-monitor exit...\n");
}
module_init(load_monitor_init);
module_exit(load_monitor_exit);
MODULE_LICENSE("GPL v2");

Makefile

OS_VER := UNKNOWN
UNAME := $(shell uname -r)
ifneq ($(findstring 4.15.0-39-generic,$(UNAME)),)OS_VER := UBUNTU_1604
endififneq ($(KERNELRELEASE),)obj-m += $(MODNAME).o$(MODNAME)-y := main.occflags-y := -I$(PWD)/
elseexport PWD=`pwd`ifeq ($(KERNEL_BUILD_PATH),)KERNEL_BUILD_PATH := /lib/modules/`uname -r`/build
endif
ifeq ($(MODNAME),)export MODNAME=load_monitor
endifall:make CFLAGS_MODULE=-D$(OS_VER) -C /lib/modules/`uname -r`/build M=`pwd`  modules
clean:make -C $(KERNEL_BUILD_PATH) M=$(PWD) clean
endif

make编译,insmod加载模块,dmesg查看日志,remod卸载模块。

细节介绍

这里主要新的东西是用到了rcu锁和定时器. 打印进程信息其实没什么要过多介绍的, 只需要留意一下遍历进程用到的宏即可.

  • rcu锁(read copy update), 顾名思义, 读, 拷贝, 更新锁. 读者不需要获取任何锁即可访问, 写者需要拷贝一个副本, 在副本上修改,在所有读操作结束之后通过一个callback回调函数将原来数据的指针指向被修改的数据. 开销更少, 适用于读多写少的情况.
  • hrtimer定时器: 区别于低精度定时器依赖系统定期产生的tick中断的定时器, hrtimer直接由系统硬件高精度定时器触发, 目前系统中由3个定时器的hrtimer到期时间分别为10ns, 100ns和1000ns.
  • 内核中的浮点数: Linux内核中对浮点数的支持不够, 因此一般使用long来保存浮点数. 代码中使用 unsigned long *ptr_avenrun 数组来保存三个时间的浮点数的, 低11位为小数部分, 高位为整数部分. 我们常用的top, uptime等命令读取的系统负载都是通过这种方式读取的.
  • 遍历进程, do_each_thread和while_each_thread两个宏定义在sched.h下, 点进去就能看到其实就是for和while.

运行实况

通过压力测试工具fio模拟io密集型任务.

参考资料

  • Linux内核分析与应用:https://next.xuetangx.com/learn/XIYOU08091001441/XIYOU08091001441/14767915/video/30179772
  • 谢宝友:Load高故障分析:https://heapdump.cn/article/1678795

http://www.ppmy.cn/news/214448.html

相关文章

华为鸿蒙笔记本电脑,华为将在6月2日发布鸿蒙平板 华为MatePad Pro

【CNMO新闻】5月28日&#xff0c;华为官方发布了预热海报&#xff0c;不难猜测全新华为MatePad Pro即将发布。这次&#xff0c;平板电脑一旦搭载鸿蒙操作系统&#xff0c;将带来怎样的新体验&#xff1f;从此前的多次鸿蒙沟通会不难知道&#xff0c;鸿蒙对于流畅度是有明显提升…

入手评测 华为MatePad 2和华为MatePad pro 2 的区别

华为MatePad Pro 2将同时拥有两种尺寸版本&#xff0c;其中一款采用12.2英寸的国产华星屏幕&#xff0c;另一款则配备了12.6英寸的三星OLED屏幕&#xff0c;均支持高刷新率。选华为MatePad 2还是华为MatePad pro 2这些点很重要看过你就懂了http://huawei.adiannao.cn 在ID设计…

达人评测华为MatePadPro2怎么样

华为MatePad Pro 2将同时拥有两种尺寸版本&#xff0c;其中一款采用12.2英寸的国产华星屏幕&#xff0c;另一款则配备了12.6英寸的三星OLED屏幕 华为MatePadPro2怎么样这些点很重要看过你就懂了http://huawei.adiannao.cn 设计方面&#xff0c;华为MatePad Pro2将整体延续前代…

达人评测 华为MatePad2和华为MatePad2 Pro 怎么样

华为MatePad2和华为MatePad2 Pro两个版本&#xff0c;采用全面屏设计方案&#xff0c;屏幕边框相对较窄&#xff0c;其中前者拥有12.6英寸和10.8英寸两个尺寸&#xff0c;后者则至少拥有一款12.2英寸版本&#xff0c;搭载高通骁龙888 4G处理器&#xff08;此前有消息称为麒麟90…

鸿蒙华为平板电脑sn号,爆料称华为MatePad 2系列平板有三个版本:预装鸿蒙OS

【天极网手机频道】由于众所周知的原因&#xff0c;华为手机/平板业务受到极大的阻碍&#xff0c;新品发布节奏明显变缓。不过根据最新消息&#xff0c;许多网友期待已久的华为MatePad Pro 2系列即将于6月2日发布并预售&#xff0c;6月10日首销。 数码博主长安数码君近日透露…

华为matepadpro能升级鸿蒙吗,华为matepadpro2021款10.8平板参数 搭载鸿蒙系统吗

华为官方此前已经宣布&#xff0c;将在 6 月 2 日发布新款 MatePad Pro&#xff0c;该平板电脑将搭载鸿蒙操作系统&#xff0c;配备全新的 HUAWEI M-Pencil 第二代手写笔。 据悉&#xff0c;新款平板电脑很可能不叫MatePad Pro 2&#xff0c;而是MatePad Pro 尺寸后缀。华为官…

华为MatePad Pro和华为MatePad区别

1、平板的屏幕方面&#xff0c;两款平板电脑的屏幕大小都是10.8英寸&#xff0c;分辨率也是一样2560x1600像素&#xff1b;华为MatePad是LCD屏&#xff0c;华为MatePad Pro是IPS触摸屏。选华为MatePad Pro还是华为MatePad这些点很重要http://www.adiannao.cn/dy 2、屏幕外观方面…

matepad能升级鸿蒙吗,华为平板有鸿蒙系统吗2021

华为鸿蒙系统即将正式上线&#xff0c;在2021年6月2日的华为鸿蒙系统发布会上&#xff0c;我们将正式看到鸿蒙系统具体的样子&#xff0c;以及它支持更新和预装的设备。根据相关消息&#xff0c;这场发布会上还将发布首款预装华为鸿蒙系统的新款期间平板电脑哦。 1、华为平板有…