sched discussion
[PATCH v2] sched/debug: Introduce per-CPU debugfs files
LLM 分析
sched/debug:引入 per-CPU debugfs 文件
系列概况
- 标题:[PATCH v2] sched/debug: Introduce per-CPU debugfs files
- 作者:Aaron Tomlin atomlin@atomlin.com
- 版本:v2(基于 v1 修订,v1 链接
20260728020309.6169-1-atomlin@atomlin.com) - 规模:单 patch,1 file changed, 43 insertions(+)
- 修改文件:
kernel/sched/debug.c - 代码统计:净增 43 行,无删除
- Message-ID:
20260728205238.18447-1-atomlin@atomlin.com - 完整性:thread 共 3 封邮件,1 patch + 2 follow-up 回复(作者自述 Sashiko 工具发现 pre-existing issues)
补丁目的
在 debugfs 中新增 per-CPU 子目录结构,让排查者无需 dump 全机所有 CPU 的 runqueue 内容,就能直接读取目标 CPU 的调度调试信息。
- 新接口路径:
/sys/kernel/debug/sched/cpu/cpu<N>/debug - 老接口路径:
/sys/kernel/debug/sched/debug(dump 所有 online CPU)
定位动机来自 reviewer(Peter Zijlstra、Zhan Xusheng)的反馈:在大型 SMP 拓扑上,定位某颗 CPU 上的 latency/调度异常时,把所有 CPU 数据全量打印既慢又干扰判断。
旧流程的问题
读取 sched/debug 会触发顶层 sched_debug_show(),依次遍历 for_each_online_cpu 把所有 CPU 的 runqueue 状态塞进一个 seq_file。对运维/调优人员来说:
- 数据量随 CPU 数量线性膨胀(256/384/512 核机器直接刷屏)。
- 难以脚本化只取某颗 CPU 的字段。
- 一旦目标 CPU 临时 offline,输出里就缺这条数据,且调用方难以区分"本来就没"与"刚好被跳过"。
新流程
新增一颗 CPU 就多一条独立的 debug 文件;读取只触发对单颗 CPU 的 print_cpu(),offline CPU 直接返回 -ENODEV:
+--- /sys/kernel/debug/sched/ (debugfs_sched) ---+
| |
| +-- debug (legacy, all CPUs) |
| |
| +-- cpu/ (new directory) |
| |
| +-- cpu0/ |
| | +-- debug --> print_cpu(cpu=0) |
| +-- cpu1/ |
| | +-- debug --> print_cpu(cpu=1) |
| +-- cpuN/ |
| +-- debug --> print_cpu(cpu=N) |
+------------------------------------------------+
读取路径上的语义(ASCII 流程图):
user reads <debug>
|
v
sched_debug_cpu_open() <-- 把 inode->i_private (=cpu) 塞给 seq_file
|
v
sched_debug_cpu_show(m, v) <-- show 回调
|
+-- cpu_online(cpu)? ----no----> return -ENODEV
|
yes
|
v
print_cpu(m, cpu) <-- 复用现有 print_cpu(),只打一颗 CPU
|
v
return 0
关键实现
补丁在 kernel/sched/debug.c 增加以下结构:
/* forward decl,使 sched_debug_cpu_show 能调到 print_cpu */
static void print_cpu(struct seq_file *m, int cpu);
/* seq_file 的 show 回调:只打目标 CPU */
static int sched_debug_cpu_show(struct seq_file *m, void *v)
{
unsigned long cpu = (unsigned long) m->private;
if (!cpu_online(cpu))
return -ENODEV;
print_cpu(m, cpu);
return 0;
}
/* open 时把 cpu 号塞进 private */
static int sched_debug_cpu_open(struct inode *inode, struct file *filp)
{
return single_open(filp, sched_debug_cpu_show, inode->i_private);
}
/* 用 single_release + seq_read 系列标准接口 */
static const struct file_operations sched_debug_cpu_fops = {
.open = sched_debug_cpu_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/* 初始化:建 cpu 目录 + 每个 possible CPU 建子目录 + debug 文件 */
static __init void debugfs_cpu_init(void)
{
struct dentry *d_cpu_dir;
unsigned long cpu;
char buf[16];
d_cpu_dir = debugfs_create_dir("cpu", debugfs_sched);
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);
}
}
并在 sched_init_debug() 末尾追加一行 debugfs_cpu_init();,使该目录树在系统启动期就建好。
类比
把它想成医院的体检中心:
- 旧的
/sched/debug像一次"全员体检报告"——全公司几百号人一起打印一摞纸,你只想看张三的心电图却拿到全员的。 - 新的
/sched/cpu/cpu<N>/debug像每人一格独立档案柜,柜门上贴着"张三""李四"标签,打开就只看那一份。 - 如果某个员工当天请假(CPU offline),柜门打开会告诉你"该员工今天不在岗"(
-ENODEV),而不是给你一份空表。
更进一步,for_each_possible_cpu() 表示把所有"理论上可能存在"的工位都预留档案柜——即便今天没人坐(offline),将来 CPU 热上线后这套接口也已就绪。
再换一种说法,像酒店的前台叫号系统:旧接口就是"今天所有住客一览",新接口是"只给我 1208 房客人的账单",空房(offline CPU)直接告诉你"无人入住"。
Highlight:风险与注意点
possiblevsonline不一致:debugfs_cpu_init()用for_each_possible_cpu一次性建好所有 CPU 的目录/文件,但sched_debug_cpu_show()用cpu_online()过滤。可能的副作用是大量已退役/未启用的 CPU 也会有空目录堆积在 debugfs 视图里,影响可读性。- 读取窗口期的并发:在
show回调里先cpu_online(cpu)再print_cpu(m, cpu),理论上仍存在读期间 CPU hotplug 下线的窗口;若打印过程触发了锁或耗时较长,可能拿到不一致快照。当前实现选择不持锁,需关注后续是否会引入 hotplug 路径的回调追踪需求。 - 路径长度与命名:路径是
…/sched/cpu/cpu<N>/debug,N越大路径越长;在大系统(>1000 核)下确认 PATH_MAX 内仍可正常 stat/open。 - debugfs 不是稳定 ABI:和已有
sched/debug一样属于调试接口,未来可以调整;但任何脚本开始依赖新路径前,需要意识到它可能在后续被重命名。 - 后续回复里作者提到 Sashiko 工具发现 pre-existing issues,本 patch 自身没有引入回归,但 review 阶段可能顺手把它们一起处理掉——这是合并前需要 follow up 的事项。
版本变化
v1 → v2 的关键调整(作者在 changelog 中明确列出):
- 动机重写:Peter Zijlstra、Zhan Xusheng 指出 v1 描述不够聚焦于"在大 SMP 上做 targeted interactive debugging",v2 把这段写进 commit message。
- offline 保护:Zhan Xusheng 建议
sched_debug_cpu_show()增加cpu_online(cpu)检查,offline 时返回-ENODEV,避免打印到一半缺数据或行为未定义。 - v1 链接补充:在 commit message 里附上 v1 的 Message-ID,便于 lore/archive 回溯。
代码层面 v2 没有 v1 之外的二次结构性变化,仅按 review 反馈补了保护与文档。
一句话总结
通过在 debugfs 下新建 /sched/cpu/cpu<N>/debug 入口,把"全 CPU 调度调试信息"拆成"单 CPU 按需读取",offline CPU 直接 -ENODEV,方便在大 SMP 上做精准定位。