sched discussion
[PATCH] sched/psi: add cpu_prio pressure metric for high-priority task stalls
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[] 机制:
psi_task_switch根据next->prio <= PSI_TASK_PRIO_THLD决定是否置位TSK_HIGH_PRIO_ONCPU,dequeue 时按 prev 优先级清位。- 新增 task count
NR_HIGH_PRIO_RUNNING,psi_group_change内随优先级变化重算 SOME/FULL。 record_times按(1 << PSI_CPU_HIGH_PRIO_TASK_SOME)/_FULL累加 stall 时长。psi_show增加分支:系统级 full 始终为 0(与现有 CPU 行为一致),cgroup 级 full 表示该 cgroup 内没有任何高优先级任务能跑的时长。- cgroup v2 注册
cpu_prio.pressure,复用cgroup_pressure_poll通知。 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:风险与注意点
- 默认阈值 118 的含义容易混淆:nice 取值 -20..19 对应 prio 100..139,118 大致对应 nice -2,覆盖"所有 RT + nice 介于 -2..19 的普通任务",范围偏大,"高优先级"名字有点名不副实。
- cgroup 已经能做同样的事:Michal 指出无需内核改动,把目标负载放进独立 cgroup,读 cpu.pressure 就是同样视角,补丁存在意义被严重削弱。
- 维护者明确拒绝:Peter Zijlstra 直接回 "Yeah, I think not.",属于硬拒而非"先改改再说"。
- DEQUEUE_PSI 传播风险:只在 rt_mutex_post_schedule 等少数 dequeue 路径加了 DEQUEUE_PSI,后续新加 dequeue 路径时若忘记同步,高优先级状态可能不会刷新。
- state_mask 复杂度提升:新增 NR_HIGH_PRIO_RUNNING 与 PSI_HIGH_PRIO_ONCPU 后,state_mask 表达变复杂,未来合并或拆分 state 时容易漏改。
版本变化
无。这是 v1,被直接否决,没有迭代版本。
一句话总结
补丁为 PSI 增加只统计高优先级任务的 CPU 压力视图,因现有 cgroup 隔离已经能做到同样效果,被 Peter Zijlstra 一句话拒绝,Michal Koutný 也补刀建议直接用 cgroup。