不修改内核镜像的情况下,使用内核模块实现高效监控调度时延

一、背景

在之前的博客 调度时延的观测_csdn 调度时延的观测 杰克崔-CSDN博客 里,我们讲了多种监控调度时延的方法,有依靠系统现有节点来监控,但是依赖系统现有节点做不到每个单词调度时延的监控,也讲了通过修改内核代码,在内核计算调度时延的地方加逻辑去监控,这里说的加逻辑也可以是新增一个tracepoint点(关于如何新增一个tracepoint点,见 内核tracepoint的注册回调及添加的方法_tracepoint 自定义回调-CSDN博客)。

这篇博客里会讲如何使用现有的tracepoint点来实现调度时延的“高效”的监控。

这里需要强调一下,“高效”,是因为如果不考虑性能的话,我们可以通过注册sched_wakeup和sched_switch这两个调度点,把每个pid的wakeup时间记下来和switch时的时间减一下来算调度时延,但是这样方式,需要保存一个大的数组来记录一个个线程的wakeup的时间,要记录就涉及到记录逻辑和查找逻辑,这些在线程数很多的情况下都是耗时的操作。另外,还得针对因为时间片到期被cpu调度出去,再调度回来的计算调度时延的场景做额外的记录和判断和运算的逻辑,因为这种情况,wakeup事件肯定是统计不到的。这样,逻辑就比较复杂了。

在第二章里,我先讲一下设计原理,然后做了一个小实验,验证了是有效果的。最后,使用per-cpu变量就可以监控每个单次的调度时延了。

二、设计原理和代码实现

2.1 设计原理

在任务切换时,调度的两个tracepoint:sched_switch和sched_stat_runtime会被依次触发,另外,在这两个tracepoint期间有调用sched_info_arrive来计算sched_switch的next进程的调度时延的逻辑,如下:

上图中delta表示的是这一次的调度时延,而run_delay统计的是这个任务的总的调度时延。

所以,我们可以在sched_switch时记下next的还没计算和累加这一次调度时延的sched_info.run_delay的值,然后在紧接着调用了sched_info_arrive后,调用sched_stat_runtime时,把累加后的sched_info.run_delay的值减去之前保存的sched_info.run_delay值,就可以算出这一次的单次的调度时延。

2.2 实验验证效果

验证时,我们就挑一个核来打印(我们选cpu序号是10的核),这样dmesg打印出来的信息不会混杂,方便验证。

验证的方法,就是打印出我们计算出来的单次的调度时延,也同时打印在 调度时延的观测-CSDN博客 博客里介绍的新增的sched_delay的tracepoint的单次的调度时延的打印,比较两个数值是否一致。如果验证一致,那么很显然,我们就可以去掉内核里新增的这个sched_delay的tracepoint了,使用原生的tracepoint就可以达到高效的监控单次调度时延的目的。

验证的核心代码如下:

可以从下图中看到是一致的:

2.3 使用per-cpu变量实现单次调度时延监控

核心代码如下:

完整的代码(为了验证,可以打开#define SCHED_DELAY_REGISTER来做时延记录的对比,验证功能完整性):

#include <linux/module.h>
#include <linux/capability.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/seq_file.h>
#include <linux/poll.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/errno.h>
#include <linux/stddef.h>
#include <linux/lockdep.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/init.h>
#include <asm/atomic.h>
#include <trace/events/workqueue.h>
#include <linux/sched/clock.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/tracepoint.h>
#include <trace/events/osmonitor.h>
#include <trace/events/sched.h>
#include <trace/events/irq.h>
#include <trace/events/kmem.h>
#include <linux/ptrace.h>
#include <linux/uaccess.h>
#include <asm/processor.h>
#include <linux/sched/task_stack.h>
#include <linux/nmi.h>
#include <asm/apic.h>
#include <linux/version.h>
#include <linux/sched/mm.h>
#include <linux/hos_kernel_kerr.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhaoxin");
MODULE_DESCRIPTION("Monitor sched delay when not add new tracepoint.");
MODULE_VERSION("1.0");struct kern_tracepoint {void *callback;struct tracepoint *ptr;bool bregister;
};static void clear_kern_tracepoint(struct kern_tracepoint *tp)
{if (tp->bregister) {tracepoint_probe_unregister(tp->ptr, tp->callback, NULL);}
}#define INIT_KERN_TRACEPOINT(tracepoint_name) \static struct kern_tracepoint mykern_##tracepoint_name = {.callback = NULL, .ptr = NULL, .bregister = false};#define TRACEPOINT_CHECK_AND_SET(tracepoint_name)                                             \static void tracepoint_name##_tracepoint_check_and_set(struct tracepoint *tp, void *priv) \{                                                                                \if (!strcmp(#tracepoint_name, tp->name))                                     \{                                                                            \((struct kern_tracepoint *)priv)->ptr = tp;                          \return;                                                                  \}                                                                            \}INIT_KERN_TRACEPOINT(sched_switch)
TRACEPOINT_CHECK_AND_SET(sched_switch)
INIT_KERN_TRACEPOINT(sched_stat_runtime)
TRACEPOINT_CHECK_AND_SET(sched_stat_runtime)//#define SCHED_DELAY_REGISTER
#ifdef SCHED_DELAY_REGISTER
INIT_KERN_TRACEPOINT(sched_delay)
TRACEPOINT_CHECK_AND_SET(sched_delay)
#endiftypedef struct sched_delay_percpu {int last_pid;u64 last_sum_delay;
} sched_delay_percpu;
#define SCHED_DELAY_PERCPU_INIT \((sched_delay_percpu){				\.last_pid = 0,	\.last_sum_delay = -1ull,  \})
DEFINE_PER_CPU(sched_delay_percpu, _sched_delay_percpu) = SCHED_DELAY_PERCPU_INIT;static void cb_sched_switch(void *i_data, bool i_preempt,struct task_struct *i_prev,struct task_struct *i_next,unsigned int i_prev_state)
{sched_delay_percpu* pdelaypercpu = this_cpu_ptr(&_sched_delay_percpu);pdelaypercpu->last_sum_delay = i_next->sched_info.run_delay;pdelaypercpu->last_pid = i_next->pid;
}#define DELAY_THRESHOLD_NS  1000000ullstatic void cb_sched_stat_runtime(void *i_data, struct task_struct *i_curr,u64 i_runtime, u64 i_vruntime)
{sched_delay_percpu* pdelaypercpu = this_cpu_ptr(&_sched_delay_percpu);u64 delay_delta;if (pdelaypercpu->last_pid == 0 || pdelaypercpu->last_sum_delay == -1ull|| pdelaypercpu->last_pid != i_curr->pid) {return;}delay_delta = i_curr->sched_info.run_delay - pdelaypercpu->last_sum_delay;if (delay_delta > DELAY_THRESHOLD_NS) {printk("comm[%s]pid[%d]tgid[%d]sched_delay[%llu]\n", i_curr->comm, i_curr->pid, i_curr->tgid, delay_delta);}pdelaypercpu->last_pid = 0;
}#ifdef SCHED_DELAY_REGISTER
static void cb_sched_delay(void *i_data, struct task_struct *i_next,unsigned long long i_delta,unsigned long long i_run_delay,unsigned long i_pcount)
{if (i_delta > DELAY_THRESHOLD_NS) {printk("cb_sched_delay:comm[%s]pid[%d]tgid[%d]sched_delay[%llu]\n", i_next->comm, i_next->pid, i_next->tgid, i_delta);}
}
#endifstatic int __init testscheddelay_init(void)
{mykern_sched_switch.callback = cb_sched_switch;for_each_kernel_tracepoint(sched_switch_tracepoint_check_and_set, &mykern_sched_switch);if (!mykern_sched_switch.ptr) {printk(KERN_ERR "mykern_sched_switch register failed!\n");return -1;}else {printk(KERN_INFO "mykern_sched_switch register succeeded!\n");}tracepoint_probe_register(mykern_sched_switch.ptr, mykern_sched_switch.callback, NULL);mykern_sched_switch.bregister = 1;mykern_sched_stat_runtime.callback = cb_sched_stat_runtime;for_each_kernel_tracepoint(sched_stat_runtime_tracepoint_check_and_set, &mykern_sched_stat_runtime);if (!mykern_sched_stat_runtime.ptr) {printk(KERN_ERR "mykern_sched_stat_runtime register failed!\n");return -1;}else {printk(KERN_INFO "mykern_sched_stat_runtime register succeeded!\n");}tracepoint_probe_register(mykern_sched_stat_runtime.ptr, mykern_sched_stat_runtime.callback, NULL);mykern_sched_stat_runtime.bregister = 1;#ifdef SCHED_DELAY_REGISTERmykern_sched_delay.callback = cb_sched_delay;for_each_kernel_tracepoint(sched_delay_tracepoint_check_and_set, &mykern_sched_delay);if (!mykern_sched_delay.ptr) {HOS_KERNEL_KLOG_ERR("mykern_sched_delay register failed!\n");return 0;}else {HOS_KERNEL_KLOG_INFO("mykern_sched_delay register succeeded!\n");}tracepoint_probe_register(mykern_sched_delay.ptr, mykern_sched_delay.callback, NULL);mykern_sched_delay.bregister = 1;
#endifreturn 0;
}static void __exit testscheddelay_exit(void)
{clear_kern_tracepoint(&mykern_sched_switch);clear_kern_tracepoint(&mykern_sched_stat_runtime);
#ifdef SCHED_DELAY_REGISTERclear_kern_tracepoint(&mykern_sched_delay);
#endiftracepoint_synchronize_unregister();printk(KERN_INFO "testscheddelay: Module unloaded.\n");
}module_init(testscheddelay_init);
module_exit(testscheddelay_exit);

下图是为了验证时延记录对比,打开了#define SCHED_DELAY_REGISTER来编译出的ko,insmod后,dmesg的打印,insmod后,我运行了若干个死循环程序,并都绑定在核10上:

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

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

相关文章

在 ASP.NET C# Web API 中实现 Serilog 以增强请求和响应的日志记录

介绍 日志记录是任何 Web 应用程序的关键方面。它有助于调试、性能监控和了解用户交互。在 ASP.NET C# 中&#xff0c;集成 Serilog 作为记录请求和响应&#xff08;包括传入和传出的数据&#xff09;的中间件可以显著提高 Web API 的可观察性和故障排除能力。 在过去的几周里&…

【开源免费】基于Vue和SpringBoot的技术交流分享平台(附论文)

博主说明&#xff1a;本文项目编号 T 053 &#xff0c;文末自助获取源码 \color{red}{T053&#xff0c;文末自助获取源码} T053&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

JVM指令集概览:基础与应用

写在文章开头 在现代软件开发中,Java 语言凭借其“一次编写,到处运行”的理念成为了企业级应用的首选之一。这一理念的背后支撑技术正是 Java 虚拟机(JVM)。JVM 是一个抽象的计算机,它实现了 Java 编程语言的各种特性,并且能够执行编译后的字节码文件。了解 JVM 的工作原…

电子应用设计方案-33:智能AI投影仪系统方案设计

智能 AI 投影仪系统方案设计 一、引言 随着科技的不断进步&#xff0c;投影仪在家庭娱乐、商务办公和教育培训等领域的应用越来越广泛。智能 AI 投影仪作为一种创新的投影设备&#xff0c;结合了人工智能技术&#xff0c;为用户带来更便捷、智能和个性化的使用体验。 二、系统…

基于springboot 的体质测试数据分析及可视化设计LWPPT

技术可行性&#xff1a;技术背景 本企业网站在Windows操作系统中进行开发&#xff0c;并且目前PC机的性能已经可以胜任普通网站的web服务器。系统开发所使用的技术也都是自身所具有的&#xff0c;也是当下广泛应用的技术之一。 系统的开发环境和配置都是可以自行安装的&#x…

SQL进阶——C++与SQL进阶实践

在C开发中&#xff0c;SQL数据库的操作是开发者常见的任务之一。虽然前面我们已经介绍了如何在C中通过数据库连接执行基本的SQL查询&#xff0c;但在实际项目中&#xff0c;我们通常需要更加复杂和高效的数据库操作。存储过程与函数的调用、复杂SQL查询的编写、以及动态构造SQL…

Spring Boot日志总结

文章目录 1.我们的日志2.日志的作用3.使用日志对象打印日志4.日志框架介绍5.深入理解门面模式(外观模式)6.日志格式的说明7.日志级别7.1日志级别分类7.2配置文件添加日志级别 8.日志持久化9.日志文件的拆分9.1官方文档9.2IDEA演示文件分割 10.日志格式的配置11.更简单的日志输入…

CSDN设置成黑色背景(谷歌 Edge)

一.谷歌浏览器 浏览器地址输入&#xff1a;Chrome://flags搜索框输入&#xff1a;enable-force-dark将default 改成 enabled&#xff0c;点击重启浏览器 二.Edge浏览器 浏览器地址输入&#xff1a;edge://flags搜索里面输入Auto Dark Mode for Web Contents将default 改成 e…

实现PDF文档加密,访问需要密码

01. 背景 今天下午老板神秘兮兮的来问我&#xff0c;能不能做个文档加密功能&#xff0c;就是那种用户下载打开需要密码才能打开的那种效果。boss都发话了&#xff0c;那必须可以。 需求&#xff1a;将pdf文档经过加密处理&#xff0c;客户下载pdf文档&#xff0c;打开文档需要…

Android内容提供者

一、ContentProvider 实现跨程序共享数据 创建内容提供者&#xff1a;extends ContentProvider类 访问数据 Uri uri Uri.parse("uri路径") 查询数据 ContentResolver resolver context.getContentResolver(); Cursor cur resolver.query(Uri,projection,sel…

基于JSP+MySQL的网上招聘系统的设计与实现

摘要 在这样一个经济飞速发展的时代&#xff0c;人们的生存与生活问题已成为当代社会需要关注的一个焦点。对于一个刚刚 踏入社会的年轻人来说&#xff0c;他对就业市场和形势了解的不够详细&#xff0c;同时对自己的职业规划也很模糊&#xff0c;这就导致大量的 时间被花费在…

如何全面备份你的Mac电脑:邮件、联系人、桌面文件和Safari书签

在卖掉或更换电脑之前&#xff0c;备份所有重要数据是非常关键的步骤。本文将指导你如何备份MacBook Pro上的邮件、联系人、桌面文件以及Safari的书签。 1. 备份Safari书签 如果你使用Safari浏览器&#xff0c;可以按照以下步骤导出书签&#xff1a; 打开Safari。点击顶部菜…

三维渲染中顺序无关的半透明混合(OIT)(一Depth Peeling)

>本文收集关于透明对象渲染技术中关于OIT技术的资料&#xff0c;尝试用简单的逻辑对这些内容进行整理。 1、透明对象的特殊对待 不要小瞧png图片和jpg图片的差异&#xff01;在一般的三维平台&#xff0c;png代表的是带透明通道的纹理&#xff0c;而jpg代表的是不带透明的…

行业分析---2024年蔚来汽车三季度财报及科技日

1 前言 在之前的博客中&#xff0c;笔者撰写了多篇行业类分析的文章&#xff08;科技新能源&#xff09;&#xff1a; 《行业分析---我眼中的Apple Inc.》 《行业分析---马斯克的Tesla》 《行业分析---造车新势力之蔚来汽车》 《行业分析---造车新势力之小鹏汽车》 《行业分析-…

mac上的建议xftp 工具

mac上的建议xftp 工具 最近使用mac比较频繁了&#xff0c;但是第一次重度使用mac里面有很多的工具都是新的&#xff0c;有的window版本的工具无法使用。 xftp 的平替 Cyberduck 从它的官网上下载是免费的&#xff0c;但是如果使用 Apple store 要花费198呢。这不就剩下一大笔…

C++ - 二叉搜索树讲解

二叉搜索树概念和定义 二叉搜索树是一个二叉树&#xff0c;其中每个节点的值都满足以下条件&#xff1a; 节点的左子树只包含小于当前节点值的节点。节点的右子树只包含大于当前节点值的节点。左右子树也必须是二叉搜索树。 二叉树搜索树性质 从上面的二叉搜索树定义中可以了…

【WRF后处理】WRF模拟效果评价及可视化:MB、RMSE、IOA、R

【WRF后处理】模拟效果评价及可视化 准备工作模型评价指标Python实现代码Python处理代码:导入站点及WRF模拟结果可视化图形及评价指标参考在气象和环境建模中(如使用 WRF 模型进行模拟),模型性能评价指标是用于定量评估模拟值与观测值之间偏差和拟合程度的重要工具。 本博客…

对拍详细使用方法

对拍的作用 对于我们在学校OJ&#xff0c;cf&#xff0c;牛客…各种只提供少量测试数据的题目&#xff0c;常常交上代码常常超时&#xff0c;能写出正确的暴力代码而题目要求的时间复杂度更低。然而这时你写出了能通过样例且时间复杂度更低的代码&#xff0c;但交上去就是错误…

D84【python 接口自动化学习】- pytest基础用法

day84 pytest常用断言类型 学习日期&#xff1a;20241130 学习目标&#xff1a;pytest基础用法 -- pytest常用断言类型 学习笔记&#xff1a; 常用断言类型 代码实践 def test_assert():assert 11assert 1!2assert 1<2assert 2>1assert 1>1assert 1<1assert a…

解析生成对抗网络(GAN):原理与应用

目录 一、引言 二、生成对抗网络原理 &#xff08;一&#xff09;基本架构 &#xff08;二&#xff09;训练过程 三、生成对抗网络的应用 &#xff08;一&#xff09;图像生成 无条件图像生成&#xff1a; &#xff08;二&#xff09;数据增强 &#xff08;三&#xff…