【Linux】测试程序怎么测 CPU 占用率?一篇讲透
前言最近做算法性能测试时遇到一个很典型的问题测试程序跑起来后怎么知道它占了多少 CPU用 top 看总感觉不够精确有没有更靠谱的办法这个问题看似简单实则踩了不少坑。网上大部分教程都在讲 top、pidstat 怎么看 CPU 占用但不同场景下该用哪个工具、结果怎么解读、有哪些坑往往语焉不详。这篇文章把整个排查过程整理出来包括Linux 查看 CPU 占用率的常用方法及适用场景怎么找到测试程序对应的进程短生命周期程序怎么测才靠谱核心结果解读与常见坑一、Linux 查看 CPU 占用率的常用方法先快速过一遍基础工具按场景选场景推荐命令日常排查top/htop看多核负载是否均衡mpstat -P ALL 1找吃 CPU 的进程ps aux --sort-%cpu | head或pidstat -u 1历史/趋势分析sar -u写脚本取数值读/proc/stat或解析mpstat1. top —— 最常用top第一行%Cpu(s)显示整体占用us用户态sy内核态id空闲率CPU 占用率 ≈ 100 - idwaIO 等待st被虚拟化偷走的时间按1展开每个核心按P按 CPU 排序按q退出。2. mpstat —— 看每个核心mpstat-PALL1# 每 1 秒刷新显示所有核心需安装sysstat。%idle是空闲率100 - %idle即该核心占用率。3. vmstat —— 整体概况vmstat15# 每秒采样共 5 次关注us、sy、id、wa列。4. ps —— 查某进程psaux--sort-%cpu|head-10# 按 CPU 占用降序取前 10ps-pPID-o%cpu,cmd# 查看指定进程5. pidstat —— 按进程持续统计pidstat-u15# 每秒采样共 5 次pidstat-u-pPID1# 只看某个进程6. sar —— 历史数据sar-u15# 实时sar-u-f/var/log/sa/sa15# 某天的历史数据7. 脚本里直接取数值读/proc/stat两次采样求差值readcpu a b c idle rest/proc/statt1$((abcidle));i1$idlesleep1readcpu a b c idle rest/proc/statt2$((abcidle));i2$idleechoCPU 占用率:$((100-(i2-i1)*100/(t2-t1)))%二、怎么找到测试程序对应的进程1. pgrep / pidof —— 按进程名pgrep-a程序名# 列出 PID 完整命令行pgrep-af关键字# -f 匹配完整命令行推荐pidof 程序名# 只输出 PID如果启动命令是./my_test --config a.txt用-f才能匹配到。2. ps grepps-ef|grepmy_test|grep-vgreppsaux|grepmy_test|grep-vgrepgrep -v grep排除 grep 自身。3. top / htop 里搜top# 运行中按 o输入 COMMANDmy_test 回车过滤# 或按 u 输入用户名只看自己的进程htop 里按F4输入名字过滤。4. 只知道端口 / 文件反查进程ss-lntp|grep端口号lsof-i:端口号ls-l/proc/*/exe2/dev/null|grepmy_testls-l/proc/*/cwd2/dev/null|grep/your/workdir5. 找到后看细节ps-fpPIDcat/proc/PID/cmdline|tr\0 # 完整启动命令含参数top-pPIDpidstat-u-pPID1常见坑现象原因 / 解决pgrep my_test查不到用pgrep -f my_test匹配完整命令行结果里有 grep 自己加grep -v grep或用pgrep -a进程名被截断15 字符用ps -ef看 CMD 列或cat /proc/PID/cmdline脚本bash/python启动进程名是解释器要用-f按脚本名查多实例pgrep -af全部列出ps -fp PID1 PID2逐个看三、核心问题短生命周期程序怎么测才靠谱程序生命周期短比如跑几秒就结束最大的问题是等你敲完 top/pidstat 命令程序可能已经结束了。针对这种场景按推荐程度给出几种方法。方案一/usr/bin/time -v最推荐一步到位/usr/bin/time-v./your_algorithm输出里直接有这几行直接读就行User time (seconds): 8.50 System time (seconds): 0.30 Percent of CPU this job got: 88% Elapsed (wall clock) time: 0:00:10Percent of CPU this job got就是整个进程生命周期内的平均 CPU 占用率已经帮你算好了。单核程序一般 ≤100%多线程程序可能 100%比如 4 线程跑满显示 400%。注意要用/usr/bin/timeGNU time不要用 shell 内置的time内置的没有-v和 CPU% 字段。如果只想要简单版time./your_algorithm# 输出 real / user / sys# CPU% (user sys) / real × 100方案二perf stat硬件级计数精度高perfstat./your_algorithm输出关键行10.012345 task-clock (msec) # 0.998 CPUs utilizedCPUs utilized就是 CPU 占用率0.998 ≈ 99.8%多线程可能 1。perf stat直接统计 CPU 周期/任务时钟不依赖时间片采样对短窗口比读/proc/stat更可靠。如果只想看利用率perfstat-etask-clock ./your_algorithm方案三脚本逐秒采样 /proc/PID/stat想看波动时用如果你不仅想要平均值还想知道程序运行期间 CPU 占用是怎么变化的比如启动峰值、稳态、结束用脚本启动程序并持续采样#!/bin/bash./your_algorithmPID$!echoPID$PID# 每 0.5 秒采样一次直到进程结束whilekill-0$PID2/dev/null;doawk{print utime$14 stime$15 (jiffies)}/proc/$PID/stat2/dev/nullsleep0.5donewait$PID更实用的版本是直接算百分比基于/proc/PID/stat的 utimestime 增量除以时间增量再除以getconf CLK_TCK#!/bin/bash./your_algorithmPID$!CLK$(getconf CLK_TCK)prev0;prev_t$(date%s.%N)whilekill-0$PID2/dev/null;dosleep1read-r_ _ _ _ _ _ _ _ _ _ _ _ _ utime stime _/proc/$PID/stat2/dev/null||breakcur$((utimestime))now$(date%s.%N)dt$(echo$now-$prev_t|bc)dcpu$((cur-prev))pct$(echoscale1;$dcpu* 100 / ($CLK*$dt)|bc)echot${dt}s CPU${pct}%prev$cur;prev_t$nowdonewait$PID方案四pidstat 配合后台启动可行但注意时序pidstat 只能监控已存在的进程程序跑得快的话需要先启动再立刻拿到 PID./your_algorithmPID$!pidstat-u-p$PID1wait$PIDpidstat 会每秒输出一行该进程的%CPU最后你再求平均。缺点是启动到 pidstat 开始采样之间可能有几百毫秒延迟会漏掉最开始的一小段。如果启动开销不重要这个方法够用。方案五top 批处理模式不推荐用于短程序./your_algorithmPID$!top-b-d1-p$PID能看但 top 的第一次采样往往不准短窗口内有效数据点少不如前面几种方法直接。四、关键注意事项1. 多核 / 多线程占用率可以 100%单线程跑满一个核 → 约 100%4 线程跑满 4 个核 → 约 400%/usr/bin/time -v的Percent of CPU和perf stat的CPUs utilized都遵循这个规则别看到 380% 就以为出错了。2. 单次测量噪声大建议多跑几次系统后台任务、频率调节、缓存冷热都会影响单次结果。建议至少跑 35 次取平均并观察离散程度foriin12345;do/usr/bin/time-f%e s, CPU %P./your_algorithmdone%P就是Percent of CPU%e是 wall time。3. 区分“启动开销”和“稳态”如果程序启动阶段有大量初始化加载模型、分配内存、预热缓存这部分会拉低平均 CPU 占用率。想测稳态性能可以在程序内部加一个“预热 计时”的机制只统计核心计算段的 CPU 时间而不是整个进程生命周期。4. 容器 / 虚拟化环境下的注意点在 Docker 或虚拟机里测 CPU 占用top显示的可能是宿主机的整体负载而不是容器实际分配到的配额。此时建议用docker stats看容器 CPU 使用用cat /sys/fs/cgroup/cpu/cpuacct.usage读容器累计 CPU 时间注意ststeal time列它表示被宿主机偷走的时间虚拟化环境下可能偏高5. 别忽略 IO 等待如果程序大量读写磁盘CPU 占用率看起来不高但实际运行时间很长。此时wa列会偏高说明瓶颈在 IO 而不是 CPU。测性能时要结合iostat一起看避免误判。五、总结场景推荐工具日常快速查看top/htop看多核分布mpstat -P ALL 1找进程pgrep -af/ps aux --sort-%cpu短程序平均占用/usr/bin/time -v最推荐高精度计数perf stat看波动曲线脚本采样/proc/PID/stat历史趋势sar -u核心结论短生命周期程序直接用/usr/bin/time -v或perf stat一步到位拿到平均 CPU 占用率想看波动再上脚本采样。别再用 top 去追一个已经跑完的程序了。