sched discussion
[PATCH] sched/debug: Introduce per-CPU debugfs files
LLM 分析
sched/debug:引入 per-CPU debugfs 文件
系列概况
- 标题:[PATCH] sched/debug: Introduce per-CPU debugfs files
- 作者:Aaron Tomlin atomlin@atomlin.com
- 版本:v1(单 patch)
- 规模:1 个 patch,6 封邮件(1 封 patch + 5 封回复)
- 修改文件:kernel/sched/debug.c
- 代码统计:+40 行,0 删除;新增 1 个 init 函数、1 个 show 回调、1 个 open 回调、1 套 file_operations
- Message-ID(首封):20260728020309.6169-1-atomlin@atomlin.com
- 完整性:完整,含 patch hunk、commit message、5 条回复;末封作者承诺出 v2 重写 commit message
补丁目的
让用户能在不遍历整台机器 runqueue 的前提下,只读取指定 CPU 的 scheduler 调试信息。
新增路径:/sys/kernel/debug/sched/cpu/cpu<N>/debug,read 时调用 print_cpu(m, cpu) 只输出该 CPU 的 runqueue 视图,避免反复 cat /sys/kernel/debug/sched/debug 后再 grep 过滤。真正的收益不是用户态解析开销,而是 dump 时不再需要为其它 N-1 个 CPU 各抢一次 rq->__lock。
旧流程的问题
旧版 /sys/kernel/debug/sched/debug 一次性 dump 所有 online CPU 的 runqueue 详情。
- 输出冗长:调试单个 CPU 也要先打印全部 CPU 的信息;
- 锁干扰大:dump 期间会逐个
raw_spin_lock_irqsave(&rq->__lock),对繁忙的大 SMP 来说本身就是噪声源; - 解析负担:用户态要 grep/sed 出目标 CPU,浪费 IO 与解析时间。
新流程
+------------------+
| user space |
| cat cpu<N>/... |
+--------+---------+
|
v
+--------+---------+
| debugfs file |
| sched_debug_cpu_ |
| fops.read |
+--------+---------+
|
v
+--------+---------+
| sched_debug_cpu_ |
| open() |
| single_open(...) |
+--------+---------+
|
v
+--------+---------+
| sched_debug_cpu_ |
| show() |
| cpu = m->private |
+--------+---------+
|
v
+------------------+
| print_cpu(m, cpu)|
| dump target rq |
| only |
+------------------+
线程里 6 封邮件的回复脉络:
[Aaron Tomlin - v1 patch]
|
+-----> [Zhan Xusheng]
| - rewrite changelog framing
| - cpu_possible vs cpu_online
|
+-----> [Peter Zijlstra]
| - "why does overhead matter?"
| - "high-freq dump = wrong"
|
+-----> [Aaron reply to Peter]
- clarifies: not for hot loops
- promises v2 rewrite
[Daniel Vacek]
- use case: isolated CPU + DPDK/FlexRAN
- agrees with patch direction
关键实现
-
前向声明
print_cpu,因为新回调要调用它:static void print_cpu(struct seq_file *m, int cpu); -
sched_debug_cpu_show:把m->private(debugfs inode 私有数据)转成 CPU 号,转手给print_cpu:static int sched_debug_cpu_show(struct seq_file *m, void *v) { unsigned long cpu = (unsigned long) m->private; print_cpu(m, cpu); return 0; } -
sched_debug_cpu_open:包装single_open,把 CPU 号以(void *)cpu形式挂到inode->i_private:static int sched_debug_cpu_open(struct inode *inode, struct file *filp) { return single_open(filp, sched_debug_cpu_show, inode->i_private); } -
sched_debug_cpu_fops:标准的single_open+seq_read组合,0444 只读。 -
debugfs_cpu_init:在debugfs_sched下建cpu/目录,再for_each_possible_cpu(cpu)给每个可能的 CPU 建cpu<N>/debug文件,把cpu强转(void *)当private字段:for_each_possible_cpu(cpu) { struct dentry *d_cpu; snprintf(buf, sizeof(buf), "cpu%lu", cpu); d_cpu = debugfs_create_dir(buf, d_cpu_dir); debugfs_create_file("debug", 0444, d_cpu, (void *) cpu, &sched_debug_cpu_fops); } -
把
debugfs_cpu_init()接到sched_init_debug()末尾,复用现有 debugfs 根目录,省去单独的开关选项。
类比
- 老接口像医院大厅的"全楼层广播叫号屏":要看 7 楼情况,必须忍受 1 到 6 楼同时刷屏;
- 新接口像每层单独的小屏幕:只点亮目标楼层,其它楼层休息不吵闹;
- 锁的获取次数从 N x per-CPU 降到 1 次,对长跑在 isolated CPU 上的低延迟任务尤其友好。
Highlight:风险与注意点
- 语义偏差:
for_each_possible_cpu与现有cpu_online_mask不一致;读 offline CPU 时会进入一个静止 rq,Zhan 指出print_cpu对 rq->curr/idle 的访问是否完全无锁仍是潜在隐患,需要 v2 评估是否改for_each_online_cpu或加锁; - commit message 论证薄弱:Peter 直接质疑"在什么场景下这份开销真的重要",并暗示"高频 dump 这种做法本身就错";这是补丁面临的最大挑战;
- 真实用例由 Daniel Vacek 补上:isolated CPU + DPDK/FlexRAN 调试,需要"看一个 CPU 就只看一个 CPU",补丁用途成立;
- 线程礼仪:Aaron 同时给 Peter 与 Zhan 解释意图,并在末封明确承诺 v2 重写 rationale;建议 v2 同时处理 possible vs online 的范围问题。
Patch 概览
只有 1 个 patch,无 patch series;详见上文"关键实现"。
版本变化
仅 v1;作者在末封邮件承诺"v2 改写 commit message",且根据 Zhan 的建议可能调整 for_each_possible_cpu 的范围或加锁策略。尚无 v2 落地。
一句话总结
为每个 CPU 暴露一个 debug debugfs 文件,让用户能零噪声、只抢一把锁地定向 dump 单个 runqueue;主要争议在 commit message 没讲清"为何这点开销值得新增接口",作者已承诺 v2 改写 rationale 并可能收敛 possible vs online 的语义。