0/3 已展开

LLM 分析

sched_ext 文档:cgroup CPU 旋钮由调度器决定

系列概况

  • 标题[PATCH v3] docs/sched_ext: document that cgroup CPU knobs are scheduler-dependent
  • 作者:Tao Cui cuitao@kylinos.cn
  • 版本:v3(单 patch 系列,从 v2 起只修改 Documentation/scheduler/sched-ext.rst
  • 规模:1 个文件,12 行新增
  • 修改文件Documentation/scheduler/sched-ext.rst
  • 代码统计:+12 / -0(一段纯文档,无 C 代码改动)
  • Message-ID:首发 20260824091501.547649-1-cui.tao@linux.dev,回复 aowxJK_KgBLLnyiN@gpd41b2f54bd-97f5-4175-9a92-34871dd6f375@linux.dev
  • 完整性:发起邮件与两位回复邮件 body 都被截断(lore 抓取不完整),但 patch 主体从 v2 起就稳定,hunk 与签名行可重建

补丁目的

让用户明确区分 fair 调度器sched_ext 调度器 在 cgroup CPU 控制接口上的语义差异:

  • fair(内核内置 CFS)会 强制执行 cpu.maxcpu.weightcpu.idle 等 cgroup v2 CPU 控制文件;
  • sched_ext 只是把这些数值 透传 给当前装载的 BPF 调度器,由后者决定是否实现、是否部分实现;
  • 提醒 nice 等传统接口同样依赖 BPF 调度器自身的实现。

修复的问题是:用户和容器编排器常误以为写在 cgroup 里的所有 CPU 限制都是内核语义,把 CPU 配额绑定到容器时可能在切到 sched_ext 后"失效",但其实是调度器没实现。

旧流程的问题

文档的 basics 章节只举了 BPF struct 例子和 simple scheduler,没有解释 cgroup 接口在 sched_ext 模型下的语义发生了什么变化。读者默认以为内核兜底,导致部署到生产时 cpu.max 数值与实际节流行为不一致。

新流程

新增一节 Scheduler-Dependent Knobs,用 12 行文字说明:

  1. fair 在内核侧强制 cgroup v2 CPU 旋钮;
  2. sched_ext 只负责调用 ops.cgroup_set_weight()cgroup_set_idle()cgroup_set_bandwidth() 等回调;
  3. 这些回调是否被实现、实现到什么程度,都取决于装载的 BPF 调度器;
  4. nice 等其他旋钮同理;
  5. 依赖时查阅装载的调度器自身文档或源码。

关键实现

patch 仅有 1 个 hunk,落在 sched-ext.rst 第 242 行附近(紧接 simple struct 示例块)。要点:

+Scheduler-Dependent Knobs
+-------------------------
+
+The fair class enforces cpu controller knobs such as ``cpu.max``,
+``cpu.weight`` and ``cpu.idle`` in the kernel. sched_ext only passes
+them to the BPF scheduler through ``ops.cgroup_set_weight()``,
+``ops.cgroup_set_idle()``, ``ops.cgroup_set_bandwidth()`` and friends.
+Whether and how a knob takes effect is up to the loaded scheduler: it
+may implement the corresponding callback partially or not at all. The
+same applies to other knobs like nice levels. When relying on these
+knobs, check the documentation or source of the loaded scheduler.

无新增 C 头文件、无 ops 改动、无示例 BPF 代码;从 v2 → v3 去掉了具体调度器名单与 nr_throttled 例子,按评审要求保持章节通用、简洁。

/* 概念上原本依赖这些内核路径(不再适用 sched_ext) */
int cpu_weight_write_u64(struct cgroup_subsystem_state *css,
                         struct cftype *cft, u64 val);
void cgroup_set_bandwidth(struct task_group *tg, u64 period, u64 quota);

类比

把 fair 调度器想成 公司自营餐厅——菜单(cpu.max 等)一写下去,后厨就照单出餐并强制执行;把 sched_ext 想成 外包食堂——菜单写下去只是通知外包服务商,由他们决定是否照做、做几分。用餐高峰(cpu.idle、nice 提升)能不能真正得到好位置,要看外包(BPF 调度器)配不配合。

流程图

       cgroup v2 CPU 文件
   (cpu.max / cpu.weight /
        cpu.idle)
              |
              | 内核解析 + subsys dispatch
              v
   +----------------------+        是 fair?         +---------------------+
   |  fair (CFS) 强制执行  | ----------------------> |   nr_throttled++    |
   +----------------------+                        |   throttled_runnable|
              |                                     +---------------------+
              | 否(sched_ext)
              v
   +----------------------+        ops.cgroup_set_*()    +-------------------+
   |   sched_ext 透传     | ------------------------->  |  BPF 调度器决定   |
   +----------------------+                              | 实现 / 部分 / 不实现|
                                                        +-------------------+

Highlight:风险与注意点

  • 风险 1(用户预期):把 K8s cpu.limits 配进容器并启用 sched_ext 后,可能完全不等价于"硬限"。运维需要在切调度器前压测。
  • 风险 2(API drift):本节列举的 ops.cgroup_set_weight() / set_idle() / set_bandwidth() 是当前名字,未来回调新增或改名(如 cgroup_set_lbandwidth)后这段文字会过时,需要同步更新。
  • 风险 3(部分实现):同一个 BPF 调度器可能只接 cpu.weight 不接 cpu.idle,业界缺少统一的"能力位图"告诉用户哪些旋钮生效,将来最好补一个 scx_capabilities 或 README 字段。
  • 跟进点:Andrea Righi 在 v2 评审里要求"concise and generic",Tao 在 v3 删掉了具体调度器名单,措辞是否还需要再 polish,可关注后续维护者收尾 ack。

版本变化

  • v2 → v3:删除调度器具体名单与 nr_throttled 示例,仅保留通用描述以避免文档被某个具体实现绑定。
  • v1 → v2(根据 Documentation/scheduler/sched-ext.rst | 12 ++++++++++++ 反推):仅做最小调整,主体章节已经稳定,新增位置不变。

一句话总结

这是 sched_ext 文档的一次小补丁:补一节"Scheduler-Dependent Knobs",明确告诉用户 cgroup v2 的 CPU 旋钮在 sched_ext 下由 BPF 调度器自行解释,fair 的强制语义不再兜底。