Linux怎么查看分时调度抢占延迟
分时调度抢占延迟指SCHED_NORMAL下可运行进程从就绪到获得CPU执行的时间差,由不可抢占区域、中断或自旋锁导致;可通过/proc/[pid]/schedstat第二列获取累计等待时间,或用getdelays -d -p PID查看单次平均抢占延迟(如10.068ms)。什么是分时调度抢占延迟
分时调度抢占延迟指SCHED_NORMAL下可运行进程从就绪到获得CPU执行的时间差,由不可抢占区域、中断或自旋锁导致;可通过/proc/[pid]/schedstat第二列获取累计等待时间,或用getdelays -d -p PID查看单次平均抢占延迟(如10.068ms)。

什么是分时调度抢占延迟
在分时调度(SCHED_NORMAL)场景里,所谓抢占延迟,说白了就是:一个已经可运行的进程,从进入就绪状态到真正拿到 CPU 开始执行,这中间被“卡住”的那段时间。它和调度延迟(scheduler latency)不是一回事,范围要更窄一些。更准确地说,是内核原本应该切换到你了,却因为还处在不可抢占区域、被更高优先级中断打断,或者自旋锁仍被占着,结果只能往后拖的那部分时间。平常业务里,这个指标常常不太显眼;但一旦碰上对时延特别敏感的服务,比如高频交易网关、实时音视频转发,它往往就是决定体验和结果的关键因素。
怎么用 /proc/[pid]/schedstat 看基础抢占等待时间
/proc/[pid]/schedstat 是最轻量、无需额外工具的观测入口,每行三个数字分别代表:
- 进程在 CPU 上实际运行的纳秒数(
sum_exec_runtime) - 在就绪队列中等待被调度的总纳秒数(
sum_wait_runtime) - 被迁移(migrate)到其他 CPU 的次数
其中第二项就是你关心的「等待调度」时间总和,但它不是单次抢占延迟,而是累计值。要观察趋势,得周期性采集:
watch -n 1 'awk "{print $2}" /proc/1234/schedstat'
注意:1234 换成目标进程 PID;该文件只在内核启用 CONFIG_SCHEDSTATS=y 时存在(主流发行版默认开启);非 root 进程只能读自己 PID 的该文件。
怎么用 getdelays 抓取单次抢占延迟分布
getdelays 是唯一能输出单次抢占延迟直方图的用户态工具,依赖内核 CONFIG_DELAY_ACCT 和 CONFIG_TASK_DELAY_ACCT。它给出的是「delayacct」统计,含真实抢占延迟(CPU 维度中的 delay a verage):
./getdelays -d -p 1234
输出中关键字段:
CPU count:该进程被调度执行的次数delay total:所有抢占等待时间总和(纳秒)delay a verage:平均每次抢占延迟(如10.068ms)
⚠️ 容易踩的坑:
- 必须用
-d参数启用 delayacct,否则只输出空值 - 进程启动前未开启 delayacct,历史数据不回溯
- 输出单位是毫秒,但精度取决于内核定时器频率(
HZ),1000 HZ 下理论最小分辨率为 1ms
为什么 top/htop 看不到抢占延迟
top 和 htop 里的 %CPU,本质上只是采样时间窗口内的平均占用率。问题就在这儿:平均值看着平稳,瞬时的抢占却会被直接“抹平”。举个例子,某个进程如果每 10ms 就被抢占 2ms,%CPU 看起来可能只有 20%,数字并不扎眼,但真实情况是每次响应都会硬生生多出 2ms 卡顿。也就是说,这类抖动,单靠 top 里的数字根本看不出来。真正要抓抢占延迟,还是得依赖内核原生统计,比如 schedstat 或 delayacct,或者直接上 tracing 工具,例如 perf sched。
复杂点在于:抢占延迟本身是“不可见事件”,没有日志、不报错、不触发告警,只在 getdelays 的 delay a verage 或 perf sched latency 的直方图里悄悄累积。一旦发现平均值 > 1ms,就得查是否开了太多实时进程、有没有长持有自旋锁、或者 sched_rt_runtime_us 配得太激进。


































