0/3 已展开

LLM 分析

sched/psi:新增 cpu_prio 压力指标(被拒绝)

系列概况

  • 标题:[PATCH] sched/psi: add cpu_prio pressure metric for high-priority task stalls
  • 作者:shisiyuan shisiyuan@lixiang.com
  • 版本:v1(无版本号标记的单版本 patch)
  • 规模:6 个文件修改,新增一个 PSI 资源 PSI_CPU_HIGH_PRIO
  • 修改文件:
    • Documentation/accounting/psi.rst
    • include/linux/psi_types.h
    • init/Kconfig
    • kernel/cgroup/cgroup.c
    • kernel/sched/core.c
    • kernel/sched/psi.c
  • 代码统计:约 +140 / -15 行(文档 +25,psi.c 主体 +60,cgroup.c +30,psi_types.h +12,init/Kconfig +18,core.c +1)
  • Message-ID:20260811104610.100617-1-shisiyuan19870131@gmail.com
  • 完整性:diff 主体清晰可读;commit body 在邮件正文中以 plain text 形式给出,但未包含 Signed-off-by

补丁目的

PSI(Pressure Stall Information)目前只能在 /proc/pressure/cpu 给出"全员"视角的 CPU 压力。

当系统同时跑大批低优先级后台任务和高优先级延迟敏感任务时,后者被普通任务挤占 CPU 的 stall 时间会被整体噪声淹没,没法独立观测。

补丁想新增 /proc/pressure/cpu_prio 和 cgroup v2 的 cpu_prio.pressure,只统计静态优先级小于等于阈值(默认 118)的高优先级任务等待 CPU 的 some / full 时长。阈值通过 CONFIG_PSI_TASK_PRIO_THLD 暴露,允许不同平台按需调整。

旧流程的问题

  • /proc/pressure/cpu 把所有可运行任务的等待时长累加在一起。
  • 一堆 nice=19 的批处理任务把 CPU 打满时,压力值非常高。
  • 同时高优先级 SCHED_NORMAL 或 RT 任务只能"沾一点点" stall 时间。
  • 用户难以判断高优先级任务到底被延迟了多少,整体指标被低优先级负载稀释。

新流程

新增 PSI 资源 PSI_CPU_HIGH_PRIO,复用 groupc->state_mask 和 times[] 机制:

  1. psi_task_switch 根据 next->prio <= PSI_TASK_PRIO_THLD 决定是否置位 TSK_HIGH_PRIO_ONCPU,dequeue 时按 prev 优先级清位。
  2. 新增 task count NR_HIGH_PRIO_RUNNINGpsi_group_change 内随优先级变化重算 SOME/FULL。
  3. record_times(1 << PSI_CPU_HIGH_PRIO_TASK_SOME) / _FULL 累加 stall 时长。
  4. psi_show 增加分支:系统级 full 始终为 0(与现有 CPU 行为一致),cgroup 级 full 表示该 cgroup 内没有任何高优先级任务能跑的时长。
  5. cgroup v2 注册 cpu_prio.pressure,复用 cgroup_pressure_poll 通知。
  6. DEQUEUE_PSI 标志被加到 rt_mutex_post_schedule 等路径,保证 psi_task_switch 在所有调度点上重算。

Patch 概览

+-------------------------+         +-------------------------+
| /proc/pressure/cpu_prio |         | cgroup2 cpu_prio.pressure|
+-------------------------+         +-------------------------+
            |                                      |
            v                                      v
   +-------------------+               +-------------------------+
   | psi_cpu_prio_show |               | cgroup_cpu_prio_pressure|
   +-------------------+               | _show                   |
            |                          +-------------------------+
            +-----> psi_show(..., PSI_CPU_HIGH_PRIO, ...)
                              |
                              v
                    groupc->state_mask
                              |
                              v
                times[PSI_CPU_HIGH_PRIO_TASK_SOME / _FULL]
                              ^
                              |
              psi_task_switch + psi_group_change
                              ^
                              |
                 next->prio / prev->prio <= PSI_TASK_PRIO_THLD ?

关键实现

/* kernel/sched/psi.c */
#define PSI_TASK_PRIO_THLD 118

void psi_task_switch(struct task_struct *prev,
                     struct task_struct *next, ...)
{
    int set = TSK_ONCPU;

    if (next->prio <= PSI_TASK_PRIO_THLD)
        set |= TSK_HIGH_PRIO_ONCPU;

    psi_flags_change(next, 0, set);
    ...
    if (prev->prio <= PSI_TASK_PRIO_THLD)
        clear |= TSK_HIGH_PRIO_ONCPU;
    ...
    if (next->prio <= PSI_TASK_PRIO_THLD) {
        clear &= ~TSK_HIGH_PRIO_ONCPU;
        if (!(prev->prio <= PSI_TASK_PRIO_THLD))
            set |= TSK_HIGH_PRIO_ONCPU;
    }
}

state_mask 中额外增加了 PSI_HIGH_PRIO_ONCPU(位编号位于 NR_PSI_STATES 之外),专门表示"有高优先级任务正在 CPU 上运行",与原有 TSK_ONCPU 不串台。

/* test_states */
if (tasks[NR_HIGH_PRIO_RUNNING] > oncpu_high_prio)
    state_mask |= BIT(PSI_CPU_HIGH_PRIO_TASK_SOME);
if (tasks[NR_HIGH_PRIO_RUNNING] && !oncpu_high_prio)
    state_mask |= BIT(PSI_CPU_HIGH_PRIO_TASK_FULL);

判定方向与原版 ONCPU 的逻辑保持一致:runnable > oncpu 视为 some,runnable 且 oncpu=0 视为 full。

类比

把 CPU 想成医院候诊大厅:

  • /proc/pressure/cpu 是"大厅总排队时长",既包括重症患者也包括划伤感冒患者。
  • /proc/pressure/cpu_prio 只统计"重症患者(优先级低于阈值)"的等待时长。
  • PSI_TASK_PRIO_THLD 相当于"什么算重症"的标准,可以由医院调整。

Peter Zijlstra 的拒绝相当于说:"医院已经分了诊室(cgroup),把重症患者放到独立诊室统计就行,没必要在系统层面再开一套重症指标。" Michal 的回复呼应了这一点:把延迟敏感任务放进独立 cgroup(即便不开 cpu controller),看那个 cgroup 的 pressure 文件就够了。

Highlight:风险与注意点

  1. 默认阈值 118 的含义容易混淆:nice 取值 -20..19 对应 prio 100..139,118 大致对应 nice -2,覆盖"所有 RT + nice 介于 -2..19 的普通任务",范围偏大,"高优先级"名字有点名不副实。
  2. cgroup 已经能做同样的事:Michal 指出无需内核改动,把目标负载放进独立 cgroup,读 cpu.pressure 就是同样视角,补丁存在意义被严重削弱。
  3. 维护者明确拒绝:Peter Zijlstra 直接回 "Yeah, I think not.",属于硬拒而非"先改改再说"。
  4. DEQUEUE_PSI 传播风险:只在 rt_mutex_post_schedule 等少数 dequeue 路径加了 DEQUEUE_PSI,后续新加 dequeue 路径时若忘记同步,高优先级状态可能不会刷新。
  5. state_mask 复杂度提升:新增 NR_HIGH_PRIO_RUNNING 与 PSI_HIGH_PRIO_ONCPU 后,state_mask 表达变复杂,未来合并或拆分 state 时容易漏改。

版本变化

无。这是 v1,被直接否决,没有迭代版本。

一句话总结

补丁为 PSI 增加只统计高优先级任务的 CPU 压力视图,因现有 cgroup 隔离已经能做到同样效果,被 Peter Zijlstra 一句话拒绝,Michal Koutný 也补刀建议直接用 cgroup。