使用funcgraph-retval和bpftrace/kprobe快速定位并解决cpu控制器无法使能的问题
版本
Linux 6.5
背景
在学习cgroupv2的时候,想给子cgroup开启cpu控制器结果失败了:
# 查看可以开启哪些控制器
root@ubuntu-vm:/sys/fs/cgroup# cat cgroup.controllers
cpuset cpu io memory hugetlb pids rdma misc
# 上面看到,是支持cpu控制器的,通过下面命令查看目前子cgroup开启了哪些控制器
root@ubuntu-vm:/sys/fs/cgroup# cat cgroup.subtree_control
memory pids
# 通过下面的命令给子cgroup开启cpu控制器
root@ubuntu-vm:/sys/fs/cgroup# echo +cpu > cgroup.subtree_control
-bash: echo: write error: Invalid argument
在给子cgroup开启cpu控制器时提示参数无效,即-EINVAL,错误码是-22.
定位
之前给linux内核的function graph增加了显示函数返回值的功能,正好可以派上用场。
- 使用下面的命令配置ftrace
echo 0 > /sys/kernel/debug/tracing/tracing_on
echo 14080 > /sys/kernel/debug/tracing/buffer_size_kb
echo ksys_write > /sys/kernel/debug/tracing/set_graph_function
echo $$ > /sys/kernel/debug/tracing/set_ftrace_pid
echo 1 > /sys/kernel/debug/tracing/options/funcgraph-retval
echo 1 > /sys/kernel/debug/tracing/options/funcgraph-retval-trim
echo function_graph > /sys/kernel/debug/tracing/current_tracer
目前社区版本还不支持funcgraph-retval-trim,这个是为了对返回值进行裁剪
然后使用下面的方法抓取log:
> /sys/kernel/debug/tracing/trace;echo 1 > /sys/kernel/debug/tracing/tracing_on; echo +cpu > cgroup.subtree_control;echo 0 > /sys/kernel/debug/tracing/tracing_on
收集到trace日志后,从上往下搜索-22错误码,看到下面的内容:
4) | cgroup_migrate_execute() {
4) | cpu_cgroup_can_attach() {
4) | cgroup_taskset_first() {
4) 0.190 us | cgroup_taskset_next(); /* = 0xffff8881003b0000 */
4) 0.551 us | } /* cgroup_taskset_first = 0xffff8881003b0000 */
4) 0.170 us | sched_rt_can_attach(); /* = 0x1 */
4) 0.180 us | cgroup_taskset_next(); /* = 0xffff888100994e00 */
4) 0.171 us | sched_rt_can_attach(); /* = 0x1 */
4) 0.180 us | cgroup_taskset_next(); /* = 0xffff88810bed4e00 */
4) 0.170 us | sched_rt_can_attach(); /* = 0x1 */
4) 0.191 us | cgroup_taskset_next(); /* = 0xffff8881083d1a00 */
4) 0.170 us | sched_rt_can_attach(); /* = 0x1 */
4) 0.170 us | cgroup_taskset_next(); /* = 0xffff888108e20000 */
4) 0.181 us | sched_rt_can_attach(); /* = 0x0 */
4) 4.248 us | } /* cpu_cgroup_can_attach = -22 */
可以看到,cpu_cgroup_can_attach先返回了-22错误码,具体分析源码:
#ifdef CONFIG_RT_GROUP_SCHED
static int cpu_cgroup_can_attach(struct cgroup_taskset *tset)
{
struct task_struct *task;
struct cgroup_subsys_state *css;
cgroup_taskset_for_each(task, css, tset) {
if (!sched_rt_can_attach(css_tg(css), task))
return -EINVAL;
}
return 0;
}
#endif
结合日志和源码,是由于sched_rt_can_attach返回了0,才会返回-EINVAL。
继续查看sched_rt_can_attach:
int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk)
{
/* Don't accept realtime tasks when there is no way for them to run */
if (rt_task(tsk) && tg->rt_bandwidth.rt_runtime == 0)
return 0;
return 1;
}
返回0的条件:进程是实时进程,但是目的task group没有给实时任务设置时间份额。
在内核文档中有下面的描述:
WARNING: cgroup2 doesn't yet support control of realtime processes and the cpu controller can only be enabled when all RT processes are in the root cgroup. Be aware that system management software may already have placed RT processes into nonroot cgroups during the system boot process, and these processes may need to be moved to the root cgroup before the cpu controller can be enabled.
上面的意思是说,在开启CPU控制器之前,需要首先将实时任务移动到根cgroup下。
那这里是哪个实时进程导致的呢?sched_rt_can_attach函数的第二个参数就是task_struct地址,可以借助bpftrace查看这个对应的哪个进程:
# cat trace.bt
#!/usr/bin/env bpftrace
kprobe:sched_rt_can_attach
{
printf("task: %lx, comm: %s\n", arg1, ((struct task_struct *)arg1)->comm);
}
运行上面的脚本,然后再次执行开启CPU控制器的操作,可以看到下面的日志:
# ./trace.bt
Attaching 1 probe...
task: ffff8881003b0000, comm: systemd
task: ffff888100994e00, comm: agetty
task: ffff88810bed4e00, comm: agetty
task: ffff8881083d1a00, comm: systemd-journal
task: ffff888108e20000, comm: multipathd
可以看到,最后一个进程是multipathd,这个进程是否为实时进程呢?
# ps -eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat,wchan:14,comm | grep -E 'PID|multipathd'
PID TID CLS RTPRIO NI PRI PSR %CPU STAT WCHAN COMMAND
153 153 RR 99 - 139 6 0.0 SLsl futex_wait_que multipathd
可以看到确实是实时进程。
下面手动将这个进程加到根cgroup下:
root@ubuntu-vm:/sys/fs/cgroup# cat /proc/153/cgroup
0::/system.slice/multipathd.service
root@ubuntu-vm:/sys/fs/cgroup# echo 153 > cgroup.procs
root@ubuntu-vm:/sys/fs/cgroup# cat /proc/153/cgroup
0::/
然后再次开启CPU控制器:
root@ubuntu-vm:/sys/fs/cgroup# echo +cpu > cgroup.subtree_control
root@ubuntu-vm:/sys/fs/cgroup# cat cgroup.subtree_control
cpu memory pids
到这里,这个问题就解决了。
如果bpftrace不能用的话,可以使用kprobe_event,下面是comm在task_struct中的偏移:
(gdb) p &((struct task_struct *)0)->comm
$1 = (char (*)[16]) 0x840
或者:
crash> *task_struct.comm -ox
struct task_struct {
[0x840] char comm[16];
}
用下面的命令添加kprobe_event,同时对ftrace进一步配置:
echo 'p sched_rt_can_attach $arg* +0x840($arg2):string' > dynamic_events
echo kprobe_ftrace_handler > /sys/kernel/debug/tracing/set_graph_notrace
echo 1 > events/kprobes/p_sched_rt_can_attach_0/enable
再次按照之前的方法复现一次,可以抓到下面的log:
2) | cgroup_migrate_execute() {
2) | cpu_cgroup_can_attach() {
2) | cgroup_taskset_first() {
2) 0.190 us | cgroup_taskset_next(); /* = 0xffff8881003b0000 */
2) 0.581 us | } /* cgroup_taskset_first = 0xffff8881003b0000 */
2) | sched_rt_can_attach() {
2) | /* p_sched_rt_can_attach_0: (sched_rt_can_attach+0x4/0x30) tg=0xffff88810a1b1c00 tsk=0xffff8881003b0000 arg3="systemd" */
2) 4.529 us | } /* sched_rt_can_attach = 0x1 */
2) 0.291 us | cgroup_taskset_next(); /* = 0xffff888107e38000 */
2) | sched_rt_can_attach() {
2) | /* p_sched_rt_can_attach_0: (sched_rt_can_attach+0x4/0x30) tg=0xffff88810a1b1880 tsk=0xffff888107e38000 arg3="agetty" */
2) 1.603 us | } /* sched_rt_can_attach = 0x1 */
2) 0.251 us | cgroup_taskset_next(); /* = 0xffff888107f3ce00 */
2) | sched_rt_can_attach() {
2) | /* p_sched_rt_can_attach_0: (sched_rt_can_attach+0x4/0x30) tg=0xffff88810a1b1880 tsk=0xffff888107f3ce00 arg3="agetty" */
2) 1.413 us | } /* sched_rt_can_attach = 0x1 */
2) 0.241 us | cgroup_taskset_next(); /* = 0xffff888107e39a00 */
2) | sched_rt_can_attach() {
2) | /* p_sched_rt_can_attach_0: (sched_rt_can_attach+0x4/0x30) tg=0xffff88810a1b1880 tsk=0xffff888107e39a00 arg3="systemd-journal" */
2) 2.324 us | } /* sched_rt_can_attach = 0x1 */
2) 0.250 us | cgroup_taskset_next(); /* = 0xffff88810862b400 */
2) | sched_rt_can_attach() {
2) | /* p_sched_rt_can_attach_0: (sched_rt_can_attach+0x4/0x30) tg=0xffff88810a1b1880 tsk=0xffff88810862b400 arg3="multipathd" */
2) 2.014 us | } /* sched_rt_can_attach = 0x0 */
2) + 15.820 us | } /* cpu_cgroup_can_attach = -22 */
kprobe_event的好处是,可以跟function_graph的日志一块结合起来看,也比较方便。
使用funcgraph-retval和bpftrace/kprobe快速定位并解决cpu控制器无法使能的问题的更多相关文章
- linux磁盘空间占满问题快速定位并解决
经常会遇到这样的场景:测试环境磁盘跑满了,导致系统不能正常运行!此时就需要查看是哪个目录或者文件占用了空间.常使用如下几个命令进行排查:df, lsof,du. 通常的解决步骤如下:1. df -h ...
- [原]调试实战——程序CPU占用率飙升,你知道如何快速定位吗?
原调试debugwindbghangprocess explorer 前言 如果我们自己的程序的CPU Usage(CPU占用率)飙升,并且居高不下,很有可能陷入了死循环.你知道怎么快速定位并解决吗? ...
- 企业IT管理员IE11升级指南【16】—— 使用Compat Inspector快速定位IE兼容性问题
企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...
- editplus快速定位到文章头部和尾部
经常用editplus发现有时文档比较长,要查找前面的内容时得一直滚动鼠标滚轮,或者拉动右侧边栏的导航标签,很少麻烦,有没有好的方法快速定位editplus到头部和尾部呢? 其实很简单,editplu ...
- postgresql异常快速定位
今天下午在使用.NET链接postgresql的时候报了“3D000”的错误,经过测试得知原来是web.config中的数据库配置问题. 在这里有个小情况需要注意,postgresql是不允许创建相同 ...
- T4 模板的调试方法,方便大家遇到问题自己快速定位和优化
T4 模板的调试方法,方便大家遇到问题自己快速定位和优化 :1. .ttinclude文件的第一行修改为 <#@ template language="C#" debug=& ...
- 快速定位隐蔽的sql性能问题及调优【转载】
在前几天,有个开发同事问我一个问题,其实也算是技术救援,他说在有个job数据处理的频率比较高,在测试环境中很难定位出在哪有问题,而且速度也还能接 受,但是在生产环境中总是会慢一些,希望我能在测试环境中 ...
- php快速定位多维数组的深度
原文地址:php快速定位多维数组的深度作者:陌上花开 自定义一个函数: function array_depth($array) { $max_depth = 1; foreach ($array ...
- Swift - 给表格UITableView添加索引功能(快速定位)
像iOS中的通讯录,通过点击联系人表格右侧的字母索引,我们可以快速定位到以该字母为首字母的联系人分组. 要实现索引,我们只需要两步操作: (1)实现索引数据源代理方法 (2)响应点击索引触发的代理 ...
- 32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看)
32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看) 昨天,大家可能都看了代码了,不知道昨天有没有在汇编代码的基础上,实现注入计算器. 如果没有,今天则会讲解,不过建议 ...
随机推荐
- buu-(ACTF新生赛2020)usualCrypt
base64的常用套路了 文件直接给base,我大胆盲猜base64: 先进sub-401080函数康康: 先看byte-40e0a0 这个很明显了,然后看上面的函数 进这连个地址发现是base64加 ...
- RocketMQ系列(一) 基本介绍
RocketMQ系列(一) 基本介绍 1.MQ 作用 MQ 的应用场景主要包含以下 3 个方面: 1.1.异步与解耦 当我们下了一个订单之后,订单服务会进行 RPC 同步调用 支付服务.库存服务.物流 ...
- Go开始:Go基本元素介绍
本文深入探讨了Go编程语言中的核心概念,包括标识符.关键字.具名函数.具名值.定义类型.类型别名.包和模块管理,以及代码块和断行.这些元素是构成Go程序的基础,也是编写高质量代码的关键. 关注Tech ...
- 使用 OpenTelemetry 构建 .NET 应用可观测性(2):OpenTelemetry 项目简介
前世今生 OpenTracing OpenTracing 项目启动于 2016 年,旨在提供一套分布式追踪标准,以便开发人员可以更轻松地实现分布式追踪. OpenTracing 定义了一套 Traci ...
- QA||TypeError: ‘module‘ object is not callable报错怎么debugIHRM接口自动化测试
unittest.py生成测试报告时执行报错:TypeError: 'module' object is not callable 代码如下 原因:结合pycharm自动标注和报错信息,分析出应该是H ...
- 自定义注解,实现请求缓存【Spring Cache】
前言 偶尔看到了spring cache的文章,我去,实现原理基本相同,哈哈,大家可以结合着看看. 简介 实际项目中,会遇到很多查询数据的场景,这些数据更新频率也不是很高,一般我们在业务处理时,会对这 ...
- 如何成功将 API 客户的 transformer 模型推理速度加快 100 倍
Transformers 已成为世界各地数据科学家用以探索最先进 NLP 模型.构建新 NLP 模块的默认库.它拥有超过 5000 个预训练和微调的模型,支持 250 多种语言,任君取用.无论你使用哪 ...
- MySQL实战实战系列 06 全局锁和表锁 :给表加个字段怎么有这么多阻碍?
今天我要跟你聊聊 MySQL 的锁.数据库锁设计的初衷是处理并发问题.作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则.而锁就是用来实现这些访问规则的重要数据结构. 根据 ...
- 探秘公有IP地址与私有IP地址的区别及其在路由控制中的作用
引言 IP地址是互联网通信中至关重要的组成部分.虽然在前一章节我们讲解了IP一些基础知识,但在我们日常生活中,我们经常听到公有IP地址和私有IP地址这两个术语.那么,公有IP地址和私有IP地址有何区别 ...
- 在线问诊 Python、FastAPI、Neo4j — 生成 Cypher 语句
目录 构建节点字典 构建Cypher CQL语句 Test 这边只是为了测试,演示效果和思路,实际应用中,可以通过NLP构建CQL 接上一篇的问题分类 question = "请问最近看东西 ...