最可靠的方法是两次读取/proc/stat计算idle时间差值再归一化:第5字段为累计空闲tick数,需间隔1–2秒采样两次,用差值除以总ticks差得到各核空闲率,超线程核因共享物理核心而高度相关。

直接看 /proc/stat 里的 idle 时间戳最可靠
Linux 内核把每个逻辑核心的累计空闲时间(单位是 USER_HZ,通常为 100)写在 /proc/stat 文件里,第 5 个字段就是 idle。它不是百分比,而是自系统启动以来的总空闲 tick 数——这正是计算“空闲率分布”的原始依据。
常见错误是只跑一次:grep '^cpu[0-9]' /proc/stat 看一眼就下结论。但单次读数毫无意义:空闲率必须基于时间差计算。正确做法是两次采样,取差值再归一化。
- 第一次采样:
grep '^cpu[0-9]' /proc/stat > stat1.txt - 等 1–2 秒后第二次采样:
grep '^cpu[0-9]' /proc/stat > stat2.txt - 用 awk 计算各核空闲占比:
paste stat1.txt stat2.txt | awk '{idle1=$5; idle2=$(NF-4); total1=$2+$3+$4+$5+$6+$7+$8; total2=$(NF-7)+$(NF-6)+$(NF-5)+$(NF-4)+$(NF-3)+$(NF-2)+$(NF-1); if (total2>total1) print "cpu" $1 ": " int((idle2-idle1)/(total2-total1)*100) "%"}'
注意:超线程逻辑核(如 cpu0 和 cpu1)可能共享物理核心,它们的 idle 值会高度相关——这不是数据错,是硬件特性。要区分物理拓扑,得查 /sys/devices/system/cpu/cpu*/topology/core_id。
mpstat -P ALL 能快速看分布,但别信单次快照
mpstat -P ALL 1 1 输出里每行的 %idle 字段,是内核对“该核在采样周期内空闲占比”的估算。它方便、带颜色、可管道处理,但底层仍依赖 /proc/stat 的两次读取——所以它本质也是差值计算,只是封装好了。
容易踩的坑:
- 间隔设太短(如
mpstat -P ALL 0.1)会导致采样抖动剧烈,%idle在 99% 和 50% 之间跳变,实际负载未必那么极端 - 没加
-P ALL默认只输出汇总行,根本看不到分布 - 输出中
CPU列为all的那行是平均值,不能代替个体观察;某核长期%idle≈ 0 而其他核 >90%,大概率是线程绑核或调度失衡
如果要做自动化分析,建议用 mpstat -P ALL 1 1 -o JSON(需 sysstat ≥11.7.3),字段明确、无格式干扰。
top 按 1 键显示的是瞬时占用率,反推空闲率不精确
top 启动后按 1,顶部出现的 %Cpu0 : 3.2 us, 0.7 sy, 0.0 ni, 96.1 id, ... 这类行,id 字段看似就是空闲率,但它其实是内核在极短时间内(毫秒级)用轮询方式估算的——不基于 /proc/stat 差值,也不保证跨核时间对齐。
这意味着:
- 多个核心的
id值加起来≠100%,因为采样时刻不同步 - 数值刷新快但抖动大,适合肉眼扫一眼“有没有明显吊车尾的核心”,不适合定量比较
- 若看到某个
%CpuX行里id长期卡在 99.9 或 0.0,更可能是采样丢失或中断风暴,不是真实空闲分布
真要验证,回到 /proc/stat 手动算两次差值,比盯着 top 刷新更稳。
别混淆“空闲率”和“频率降频”
有人看到 cpu MHz 字段掉到 800.000 就以为核心“空闲了”,这是典型误解。空闲率(idle time)和运行频率(cpu MHz)是两个正交指标:
- 一个核心可以
%idle = 99%但频率仍维持在 3.2GHz(比如 Intel 的 Speed Shift 技术不立即降频) - 也可以
%idle = 0%却被电源策略锁在 1.2GHz(如cpupower frequency-set -g powersave) - 查空闲分布,盯
/proc/stat或mpstat;查频率波动,用cpupower monitor或反复读/proc/cpuinfo
真正容易被忽略的是:空闲率反映的是“时间维度上 CPU 在干什么”,而频率反映的是“此时电压/时钟设定”。两者都重要,但混着看会误导根因判断。


















