使用funcgraph-retval和bpftrace/kprobe快速定位并解决cpu控制器无法使能的问题

这篇具有很好参考价值的文章主要介绍了使用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控制器的操作,可以看到下面的日志:

root@ubuntu-vm:~# ./trace.bt
Attaching 1 probe...
task: ffff8881003b0000, comm: systemd
task: ffff888107e38000, comm: agetty
task: ffff888107f3ce00, comm: agetty
task: ffff888107e39a00, comm: systemd-journal
task: ffff88810862b400, 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

上面$arg*的用法是新版本的内核才有的,借助BTF来获取函数的入参,比之前方便多了,可以用来输出函数的全部入参

这个方法跟funcgraph-retval结合起来,既实现了输出内核函数的入参,同时也输出了内核函数的返回值

再次按照之前的方法复现一次,可以抓到下面的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的日志一块结合起来看,也比较方便。上面的日志显示调用sched_rt_can_attach时,当进程是multipathd时,返回了0,进而导致cpu_cgroup_can_attach返回了-22.文章来源地址https://www.toymoban.com/news/detail-749055.html

到了这里,关于使用funcgraph-retval和bpftrace/kprobe快速定位并解决cpu控制器无法使能的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • flask----内置信号的使用/django的信号/ flask-script/sqlalchemy介绍和快速使用/sqlalchemy介绍和快速使用

    内置信号的使用 有哪些内置信号 自定义信号 # 1 第一步:定义一个自定义 信号 # 2 第二步:写个函数 # 3 第三步:函数跟自己定义信号绑定 # 4 第四步:触发自定义信号---》我们做   信号的作用(信号量--》Semaphore) 信号量 sqlalchemy的原生操作

    2024年02月14日
    浏览(40)
  • RabbitMQ快速使用代码手册

    本篇博客的内容为RabbitMQ在开发过程中的快速上手使用,侧重于代码部分,几乎没有相关概念的介绍,相关概念请参考以下csdn博客,两篇都是我找的精华帖,供大家学习。本篇博客也持续更新~~~ 内容代码部分由于word转md格式有些问题,可以直接查看我的有道云笔记,链接:

    2024年02月09日
    浏览(38)
  • Processing快速使用

    -----processing的代码编写流程主要包括2部分,setup()和draw(),等同于Start()和Update()。setup用于设置程序的属性,如画布的大小、背景色、要导入的图片、字体等。draw用于循环执行绘图指令,如点、线、圆、图片等等。 代码区分大小写,所有语句以分号\\\";\\\"结尾。 -----变量类型:

    2024年01月21日
    浏览(45)
  • 快速使用Spring Cache

     哈喽~大家好,这篇我们来看看快速使用Spring Cache。  🥇个人主页:个人主页​​​​​                        🥈 系列专栏:【日常学习上的分享】 🥉与这篇相关的文章:                        Redis快速入门及在Java中使用Redis Redis快速入门及在Java中使用Redis_程序

    2024年02月08日
    浏览(58)
  • 快速使用Git完整开发

    本系列有两篇文章: 一是本篇,主要说明了关于 Git 工具的基础使用,包含三板斧( git add 、 git commit 、 git push )、 Git 基本配置、版本回退、分支管理、公钥与私钥、远端仓库和远端分支、忽略文件、命令别名、标签等内容。 二是另外一篇《Git结合Gitee的企业开发模拟》,

    2024年02月10日
    浏览(32)
  • git快速使用

    设置签名 工作区:写代码的地方。 暂存区:.git的.index 工作区:.git 本地coding git init, 初始化一个本地仓库,项目根目录下会出现个.git git remote add origin git@github.com:QiuliangLee/git_test.git, 和远程库进行关联。这里是我在github创建了一个git_test仓库,我需要让本地和这个仓库进行

    2024年02月10日
    浏览(28)
  • kafka使用教程、快速上手

    Kafka 是一个分布式的基于发布 / 订阅模式的消息队列(Message Queue),主要应用于大数据实时处理领域。 1.2.1 传统消息队列的应用场景 使用消息队列的好处: 解耦 允许独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。 可恢复性 系统的一部分组件失效时

    2023年04月14日
    浏览(49)
  • RabbitMQ 的快速使用

    docker部署rabbitmq     导入RabbitMQ依赖 pom.xml   提供者和消费者的配置 application.yml   消息转换器 提供者和消费者都可以添加 RabbitMQMessageConverterConfig.java   注意执行顺序 :需要先使用consumer监听并创建队列(需要保证队列存在!),publisher再往里面添加队列才会有用,否则白添加

    2024年02月10日
    浏览(38)
  • Eureka使用快速入门

    本文主要对Eureka的使用进行简单记录,主要作为个人日后复习笔记所用,不建议初学者阅读。 user-service会每隔一段时间(默认30秒)向eureka-server发起请求,报告自己状态,称为心跳 当超过一定时间没有发送心跳时,eureka-server会认为微服务实例故障,将该实例从服务列表中剔除

    2024年02月14日
    浏览(40)
  • Docker 的快速使用

    ubuntu安装 centos安装 安装完毕之后执行一下这条命令,可以避免每次使用docker命令都需要sudo权限 阿里云docker镜像加速 DockerHub 遇到不懂或者不会使用的命令可以使用 docker --help 查看文档   使用docker时需要特别注意 防火墙 和 端口占用     镜像 相关命令 镜像是将应用程序及其

    2024年02月11日
    浏览(20)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包