sched-ext discussion
[PATCH v2] sched_ext: Add tracepoint for scheduler exit
LLM 分析
系列基线信息
- 标题:[PATCH v2/v3] sched_ext: Add tracepoint for scheduler exit
- 作者:Pat Somaru patso@likewhatevs.io
- 版本演进:v2 → v3(v1 在引用链接中,未在本 thread 内)
- 规模:v2 改动 25 行(2 文件),v3 改动 36 行(3 文件)
- 来源通道:sched-ext(LORE)
- thread_key(v1 的 Message-ID):
20260512055632.1096713-1-patso@likewhatevs.io - 落地状态:Tejun Heo 在 v3 后
Applied to sched_ext/for-7.3,已合入 sched_ext 分支
明确目的
sched_ext 调度器的退出处理路径(scx_claim_exit())目前只能在出问题时通过 scx_dump 打印一份"静态"的快照——它把内核态 scheduler 状态和 BPF 程序状态导出,但调用时机和导出格式是被固化死的。
本补丁的目的是:
- 加一个 tracepoint(
sched_ext_exit),让外部 BPF 程序能在 scheduler 退出这一事件发生时动态挂上来读取状态,而不是依赖调度器内置的 dump。 - 把正在退出的
struct scx_sched *透传给 handler,这样 BPF 端能借助 tracepoint 上下文读sch上的字段(name、level、kind...)。 - 由于 sched_ext 支持 sub-scheduler 层级(一个父调度器下挂若干子调度器,退出事件会在层级间传播),tracepoint 必须能区分"哪一层、哪个 cgroup 下的 scheduler 实例",否则多个同名同 level 的子实例事件会搅在一起。
遍历代码
整条线一共有 3 个文件、2 个关键位置:
1. include/trace/events/sched_ext.h:定义 tracepoint 格式
v2 版本定义:
TP_PROTO(struct scx_sched *sch, __u32 kind)
TP_ARGS(sch, kind)
TP_STRUCT__entry(
__string(name, sch->ops.name)
__field (__s32, level)
__field (__u32, kind)
)
TP_fast_assign(... name/level/kind ...)
TP_printk("sched %s level %d kind %u", ...)
v3 在收到 Tejun 评审后增加了两个字段:
__field (__u64, sub_cgroup_id)
__string(cgrp_path, sch_cgrp_path(sch))
`TP_fast_assign` 和 `TP_printk` 同步扩展。`sub_cgroup_id` 来自 `sch->ops.sub_cgroup_id`,`cgrp_path` 通过新引入的 helper `sch_cgrp_path(sch)` 取。
### 2. `kernel/sched/ext/ext.c`:在退出路径触发 tracepoint
patch 只在 `scx_claim_exit()` 里增加一行 `trace_sched_ext_exit(sch, kind);`。这是关键决定 tracepoint 触发时机的位置——每个 scheduler 通过 `scx_claim_exit()` 宣告自己即将退出时都会路过。
### 3. `kernel/sched/ext/sub.h`:新增 `sch_cgrp_path()` helper
v3 新增的小工具函数:
static inline const char *sch_cgrp_path(struct scx_sched *sch)
{
return sch->cgrp_path;
}
考虑 `CONFIG_EXT_SUB_SCHED` 没开的情况,再提供一个 fallback 返回 `"/"` 的 inline 实现,避免在 `trace_sched_ext_exit()` 用到时出现"未声明"。
### 4. 调用时(v3 测试输出)
bpftrace -e 'rawtracepoint:sched_ext_exit { ... }'
grep 'sched_ext_exit:' /sys/kernel/tracing/trace
scx_mitosis-51 [000] ...1. 30.552740: sched_ext_exit:
sched mitosis_1.1.0_x86_64_unknown_linux_gnu level 0
sub_cgroup_id 0 cgrp_path / kind 64
可以同时看到 rawtracepoint(拿 `arg0`/`arg1` 指针)和 tracepoint 格式化输出两种用法都正常。
### 版本演进(v2 → v3)
- v2:tracepoint 只记录 `name + level + kind`
- Tejun 指出"同名同 level 的 sibling cgroup 下的子调度器没法区分"
- v3:增加 `sub_cgroup_id` + `cgrp_path` 两个字段,同时新增 `sch_cgrp_path()` helper 包装
## ASCII 流程图
### 调度器退出 + tracepoint 触发时序
┌──────────────────────┐
│ external signal/ │
│ scx_bpf_exit() 等 │
└──────────┬───────────┘
│
▼
┌──────────────────────┐ 每个 scheduler 实例
│ scx_claim_exit(sch, │ ──► 一次(含父子层级)
│ kind) │
└──────────┬───────────┘
│
├─────────────────────┐
▼ ▼
┌──────────────────┐ ┌──────────────────────┐
│ WRITE_ONCE( │ │ trace_sched_ext_exit │ ← 新增的 hook
│ sch->aborting, │ │ (sch, kind) │
│ true) │ └──────────┬───────────┘
└──────────────────┘ │
▼
┌────────────────────────────────────────────────────┐
│ BPF / bpftrace 消费者 │
│ ─ rawtracepoint: 拿 arg0 = sch* 读任意字段 │
│ ─ /sys/.../trace: 拿到格式化行 │
│ "sched <name> level <lvl> sub_cgroup_id <id> │
│ cgrp_path <path> kind <k>" │
└────────────────────────────────────────────────────┘
### sub-scheduler 层级下事件归属混乱
父调度器 (mitosis, level=0, cgrp=/)
│
├──► 子实例 A (mitosis, level=1, cgrp=A) ── exit ──► event
│ name=A
│ level=1 ← 碰撞!
├──► 子实例 B (mitosis, level=1, cgrp=B) ── exit ──► event
│ name=B
│ level=1 ← 碰撞!
│
v2: 看 name+level → 无法区分 A、B 两条
v3: 用 sub_cgroup_id / cgrp_path → 能区分
### 文件改动关系图
include/trace/events/sched_ext.h (tracepoint 定义)
▲
│ TRACE_EVENT(sched_ext_exit)
│
kernel/sched/ext/ext.c ──► trace_sched_ext_exit(sch, kind)
│
│ sch->ops.sub_cgroup_id
│ sch_cgrp_path(sch)
▼
kernel/sched/ext/sub.h ──► sch_cgrp_path() helper
▲
│
CONFIG_EXT_SUB_SCHED 决定实现细节
## 概念类比
把 sched_ext 想象成一家**分店连锁的总部**:
- **scx_sched**:每一家店(一个调度器实例)。同一家连锁(同一个 BPF 程序 = mitosis)可以在不同 cgroup 下开多家"分店"。
- **scx_claim_exit**:店铺准备关门打烊的流程,会送一份"关门信号"上来。
- **scx_dump**:总部事前打印好的一张"关门交接清单模板"——格式是死的。
- **sched_ext_exit tracepoint**:在门口装一个**摄像头 + 通知器**,每家分店关门时就触发,外部的人(bpftrace / 监控系统)可以临时冲过来拍下那一瞬间的内部状态。
- **sub_cgroup_id / cgrp_path**:相当于每家分店的**门牌号 + 街道地址**——只看品牌名(mitosis)和"是几级分店"(level)分辨不出两家一模一样的分店,但加上门牌号就能精确指认。
- **kind**:关门原因,是"营业结束正常关门"还是"安全检查不通过被迫关门"。
## Highlight 突出问题
1. **跨 cgroup 子实例的事件混淆风险**:v2 仅用 `name + level` 标识单个 scheduler 实例,在 sub-scheduler 层级 + sibling cgroup 同程序实例下会出现"两条事件看起来一样"的情况;这是被 Tejun 一眼抓到的关键缺陷。**v3 通过加 `sub_cgroup_id + cgrp_path` 解决**。
2. **tracepoint 上下文选择**:`scx_claim_exit()` 是 scheduler"声称要退出"的统一入口,但要意识到 sub-scheduler 通过 dedicated helper kthread **并行**退出,多个 tracepoint 事件可能在不同 CPU 上同时触发;任何 BPF 端 handler 必须假设并发(即便该 scheduler 实例退出了,事件写历史时也无锁可言)。
3. **字段稳定性的取舍**:tracepoint 一旦发布就成了 ABI;`sch_cgrp_path()` 返回值是 `sch->cgrp_path`,其生命周期要保证在 tracepoint 写完之前有效。`sch` 还在 `claim_exit` 持有引用阶段,目前是安全的,但后续 reviewer 仍需确认整个 claim 到 trace 期间 cgrp 没有被释放。
4. **scx_dump 与 tracepoint 互补**:tracepoint 不是要替代 `scx_dump`,而是提供一个**可编程、可观察、可定制**的出口;后续如果想做"自动 panic 报告"或"per-instance 退出统计",tracepoint 是更灵活的基础设施。
## 版本演进总结
- **v1**(未贴出,引用链接):最初版本。
- **v2**:加入 tracepoint + `scx_claim_exit` 调用点;只暴露 name/level/kind。
- **Tejun 评审**:指出 sibling cgroup 同程序实例下 name+level 不足。
- **v3**:补 `sub_cgroup_id` + `cgrp_path` 以及 `sch_cgrp_path()` helper(含 `!CONFIG_EXT_SUB_SCHED` fallback)。
- **应用**:Tejun `Applied to sched_ext/for-7.3`,进入 7.3 合并窗口。
## 与其他相关 patch 系列的关联
- 同主题**早期 v1 系列**(Message-ID `20260512055632.1096713-1-patso@likewevs.io`)是本系列的前身,方向一致、本 thread 不再讨论。
- 现有的 `sched_ext_bypass_lb` 等 tracepoint(补丁在 sched_ext.h 同一文件的紧邻位置新增)属于同类基础设施扩展,可视为 sched_ext 在 observability 上整体投入的一部分。
- `scx_dump` 路径与本补丁**互补而非替代**:dump 提供的是退出时的"自动 dump",tracepoint 提供的是"用户可编程抓取"。
## 一句话总结
为 sched_ext 的 `scx_claim_exit()` 新增一个 `sched_ext_exit` tracepoint,让 BPF 程序能在调度器退出时动态观察状态;v3 通过补 `sub_cgroup_id` 和 `cgrp_path` 解决了 v2 在 sub-scheduler 同名/同 level 实例下事件归属不清的问题,最终被 Tejun Heo `Applied to sched_ext/for-7.3`。
---