vmstat_shepherd 的职责
周期巡检
deferrable work
每个 CPU 一个
vmstat_work
发现计数差异
need_update(cpu)
巡检循环
for_each_online_cpu(cpu)
跳过 isolated CPU
cond_resched() 让出 CPU
发现差异就排一次
if (!delayed_work_pending(dw) &&
need_update(cpu))
queue_delayed_work_on(..., 0);
为什么要防重复
重复刷新不增加信息,只增加开销
还会在 flush 过程中反复取 zone 锁
旧判断:delayed_work_pending()
delayed_work_pending(dw)
-> work_pending(&dw->work)
-> WORK_STRUCT_PENDING_BIT
它只回答一个问题
已排队
pending = 1
正在执行
pending = 0
排队时能挡住重复
执行时挡不住
pending 位何时清
worker 取走 work
-> clear PENDING
-> 开始执行
执行中的 work 不再 pending
问题不在“排过没有”,而在“现在是否在跑”
旧检查把 running 误判成 idle
双重调度的窗口
shepherd 检查
pending = 0
update 正在跑
计数尚未清零
need_update
仍为 true
再排 delay 0
同一 CPU 再跑一次
检查与执行交错,pending 位看不到 running
72 核上的观测
许多间隔 < 500 jiffies
最极端:0 jiffies
同一 jiffy 内调用两次
不是无害的重复
每次 update 都扫 zone
刷新计数、衰减 PCP
后面展开 zone 锁
这是执行态与 pending 位的语义错位,不是偶发调度抖动
一行替换
旧
!delayed_work_pending(dw)
只看 pending 位
新
!work_busy(&dw->work)
pending 或 running 都算忙
queue_delayed_work_on() 与刷新路径不变
work_busy() 看什么
WORK_BUSY_PENDING
WORK_BUSY_RUNNING
两者任一 -> 返回非零
shepherd 的判断
排队中:跳过
正在跑:跳过
空闲且有差异:才排
只换判断函数,不改队列与刷新路径
修复前
间隔 0 jiffies
大量 < 500 jiffies
系统性双重调度
守护反复把同一 CPU
从 idle 误判成可排
修复后
sub-jiffy 消失
多数 sub-100-jiffie 消失
残余 700–999 jiffies
偶尔早到,但不再是
系统性的二次调用
700–999 从哪来
round_jiffies_relative(sysctl_stat_interval)
对齐到更近的 jiffie-second 边界
与这个 race 无关
修复压掉系统性重复,不承诺零重复
剩余窗口见最后一章
一次多余 update 的代价
refresh_cpu_vm_stats(true)
for_each_populated_zone
decay_pcp_high()
decay_pcp_high()
pcp->high 高于 high_min
-> 下调 high
count 超过 high
-> 触发 drain
free_pcppages_bulk()
把空闲 PCP 页倒回 buddy
每次取 zone 自旋锁
重复 update -> 反复竞争
所以双重调度不只是多一次函数调用
它把 zone 锁竞争放大
大机器上更明显
测量条件
72-CPU 系统 · stress-ng · perf lock contention
free_pcppages_bulk 竞争
~-55%
竞争次数
perf lock contention
~-57%
总等待时间
free_pcppages_bulk
~-47%
最大等待时间
free_pcppages_bulk
收益边界
这是 free_pcppages_bulk 的锁竞争指标
不是所有 workload 的吞吐承诺
work_busy() 仍不是原子判断
检查 work_busy
此刻不忙
work 刚好跑完
离开 running
queue 仍可能发生
第二次调用
检查与入队不是一个原子步骤
残余窗口的后果
这次不 pending 也不 running
shepherd 仍可能再排一次
罕见,只产生偶尔小间隔
为什么仍然值得
旧:系统性重复
新:罕见窗口
判断成本很低
一行判断替换:从“排过没有”到“现在忙不忙”
保留快速刷新,削掉系统性双重调度
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x