0/11 已展开

LLM 分析

sched/idle:修复 no-cpuidle-driver 路径的 Sysbench 回归

系列概况

  • 标题:线程主题为 [REGRESSION] sched/idle: Sysbench threads regression after f4c31b07b136;修复补丁为 [PATCH] sched/idle: Stop the tick when no cpuidle driver is available
  • 作者:Joseph Salisbury 发起报告;Christian Loehle 提交修复;Rafael J. Wysocki 和 Zhan Xusheng 参与分析。
  • 版本:没有可靠的内核版本号、vN 编号或目标发布周期。
  • 规模:共 11 封邮件,包含 1 个单行修复 patch;测试覆盖 x86 与 Arm/Ampere 两种 OCI VM shape。
  • 修改文件kernel/sched/idle.c
  • 代码统计:1 file changed,1 insertion(+),1 deletion(-)。
  • Message-ID:线程首封为 096b42fa-107f-450d-b3b1-03bcad3f1e04@oracle.com;修复 patch 为 0b9b9c3d-8ba0-4329-9504-b9d33c627649@arm.com
  • 完整性:输入包含回归报告、bisect 结果、revert 验证、根因推演和修复 patch;但多封回复只是截断引用,未包含最终评审结论、修复后完整测试数据或合入状态。

补丁目的

Oracle 在两个 OCI VM shape 上发现 MySQL Sysbench threads 性能可复现下降,bisect 将首个坏提交定位为 f4c31b07b136

  • VM.Standard2.1:333 降至 236,下降 29.1%。
  • VM.Standard.A1.Flex.2:1286 降至 1152,下降 10.4%。

回退该提交后性能恢复。修复 patch 收窄改动范围:仅让没有 cpuidle driver 的路径恢复无条件停止 tick;single-state cpuidle 路径继续使用 got_tick 启发式。

旧流程的问题

f4c31b07b136 之前,两条特殊路径的语义不同:

  • 没有 cpuidle driver:调用 tick_nohz_idle_stop_tick(),然后进入 default_idle_call()
  • 只有一个 cpuidle state:调用 tick_nohz_idle_retain_tick(),保留周期 tick。

问题并非旧代码本身,而是 f4c31b07b136 将两条路径统一到 idle_call_stop_or_retain_tick(got_tick)。在新的 idle episode 开始时,got_tick 通常为 false,使 no-driver guest 暂时保留周期 tick。

按 Zhan Xusheng 的推演,guest 因仍有约 1/HZ 的 pending timer,更容易被 hypervisor 唤醒和调度。该解释与测试幅度相关,但不能视为已经完全证实的唯一根因。

新流程

修复 patch 将 no-driver 分支改为直接调用 tick_nohz_idle_stop_tick(),恢复每次进入 idle 时都立即停 tick 的语义。存在 cpuidle driver 的路径不受该单行修复影响,single-state 路径仍保留 previous-wakeup 启发式。

+----------------------+       +--------------------------+
| no cpuidle driver    |       | cpuidle driver available |
+----------+-----------+       +------------+-------------+
           |                                |
           v                                v
+----------------------+       +--------------------------+
| stop tick now        |       | use previous got_tick     |
+----------+-----------+       +------------+-------------+
           |                                |
           v                                v
+----------------------+       +--------------------------+
| default_idle_call    |       | enter configured idle     |
+----------------------+       +--------------------------+
           |                                |
           +----------------+---------------+
                            |
                            v
                 +----------------------+
                 | idle loop continues  |
                 +----------------------+

Patch 概览

修复来自 Christian Loehle,是原始回归线程的直接后续补丁。它没有回退整个 f4c31b07b136,而是恢复其中 no-cpuidle-driver 路径的旧行为。

补丁使用 Fixes: f4c31b07b136 标记回归来源,并使用 Reported-by 标明 Joseph Salisbury。线程没有提供其他可确认的相关 patch 系列。

关键实现

逻辑变化可以概括为:

if (cpuidle_not_available(drv, dev)) {
        tick_nohz_idle_stop_tick();
        default_idle_call();
        goto exit_idle;
}

/* The single-state cpuidle path retains the got_tick heuristic. */
idle_call_stop_or_retain_tick(stop_tick);

关键步骤如下:

  1. do_idle() 在新 idle episode 开始时将 got_tick 重置为 false
  2. 统一后的 helper 以 false 进入时选择 retain tick 分支。
  3. 只有 tick 实际触发并令 got_tick 变为 true 后,后续循环才更可能停止 tick。
  4. 修复直接调用 tick_nohz_idle_stop_tick(),不再等待这次 got_tick 状态转换。
  5. single-state cpuidle 路径继续保留启发式,修复没有扩大为完整回退。
new idle episode
      |
      v
got_tick = false
      |
      v
no-driver + unified heuristic ----> retain tick
      |                                  |
      |                                  v
      |                           host sees timer soon
      |                                  |
      |                                  v
      |                           more vCPU wakeups
      |
      v
direct tick_nohz_idle_stop_tick()
      |
      v
old no-driver behavior restored

类比

可以把 vCPU 想成值班室里的员工,把周期 tick 想成固定响铃闹钟:

  • 旧流程允许员工每次休息时马上关闭闹钟,宿主便能暂时离开,减少无意义查看。
  • 新启发式会参考员工上次为何醒来;第一次进入休息时信息不足,闹钟仍保持启用。
  • hypervisor 看见闹钟很快又要响,就会更频繁地唤醒和安排这个 vCPU。
  • 修复相当于为没有完整 idle 状态管理的值班室恢复特殊规则:先关闹钟,再让员工休息。

Highlight:风险与注意点

  • got_tick 解释是线程中的合理根因推演,尚缺 idle-state、hypervisor 调度或 trace 数据来最终确认。
  • 邮件曾要求提供 guest 与 host 的 idle-state 列表,但当前输入没有这些信息。
  • HZ 差异与回归幅度一致:回复称 x86 为 HZ=1000、退化 29%;Arm 为 HZ=250、退化 10%。这支持频率相关假设,但不单独构成证明。
  • 修复只覆盖 no-driver 路径;single-state cpuidle 场景仍需继续观察。
  • 缺少修复后的完整复测数据,patch 正文也明确表示作者仍好奇精确机制。

版本变化

线程没有 vN 编号,但语义变化清晰:

  • f4c31b07b136:统一 no-driver 与 single-state 两条特殊路径,引入 previous-tick-wakeup 启发式。
  • 后续修复 patch:仅恢复 no-driver 路径的无条件停 tick 行为,保留 single-state 路径的启发式。
  • 尚未提供 v2、最终测试结果或合入状态。

一句话总结

f4c31b07b136 将 previous-wakeup 启发式带入无 cpuidle driver 的 guest idle 路径,导致 tick 保留并可能增加 vCPU 唤醒开销;一行修复恢复了该路径原有的立即停 tick 行为。