perf stat 组合硬件计数器分析 CPU 周期
分析 CPU 周期时,先用 perf stat 同时采集 cycles 和 instructions,再用周期数除以指令数得到 CPI。这样能把“程序慢”拆成可观察的计数器关系,而不是只看一次墙上时钟时间。Linux 内核文档说明,perf stat 会借助现代 CPU 中的硬件计数器统计软硬件事件。
官方文档:https://docs.kernel.org/admin-guide/workload-tracing.html
下面的示例只展示命令写法和解释方法,配图是静态说明图,不是本机运行截图,也不代表某台机器已经产生了固定数值。
先把 perf stat 的三层对象分开
这条命令里有三个容易混淆的对象:
- 事件名:例如
cycles、instructions和branches,描述想数什么。 - PMU 计数器:CPU 提供的性能监控单元,负责在硬件层累计事件。
- perf stat:把事件配置、启动/停止计数、缩放和结果展示串起来的用户态工具。
因此,看到某个事件显示为不可用时,首先要判断是 CPU、内核、虚拟机还是权限没有提供它,而不是立刻把它解释为程序没有执行相关操作。

先用 perf list 确认当前机器能看到什么
硬件事件不是所有机器都完全相同。先列出当前 perf 能识别的事件,再决定组合方式:
# 列出当前环境可见的事件,先确认名称再写统计命令
perf list
# 只筛选周期、指令和分支相关事件,便于快速阅读清单
perf list | grep -E 'cycles|instructions|branches'
如果清单中没有预期的通用事件,可能是 CPU PMU 暴露方式不同、内核配置不同,或者运行在限制硬件计数器的虚拟机里。不要把网上另一台 CPU 的事件别名原样搬过来;以当前机器的 perf list 结果为准。
用一条命令组合 CPU 周期和指令数
对一个稳定的工作负载,可以先使用最小组合:
# 同时统计 CPU 周期与退休指令,sleep 只是一个占位工作负载
perf stat -e cycles,instructions -- ./your-program --input sample.dat
# 再加入分支事件,观察控制流相关的额外线索
perf stat -e cycles,instructions,branches,branch-misses -- ./your-program --input sample.dat
-e 后用逗号分隔事件。-- 用来明确后面的内容是被测程序及其参数,避免程序自己的参数被 perf 误解。示例中的程序名、参数和文件只是写法占位,实际采集时应替换成可以重复运行的真实工作负载。
硬件计数器数量有限时,perf 可能分时复用事件,结果会带有缩放信息;如果事件组合过多,还可能出现无法调度或某个计数器不可用。第一轮建议只保留能回答当前问题的两个到四个事件。
让每次采集可以被比较
单次运行只能说明一次运行的计数结果。要比较优化前后,至少固定输入、参数、CPU 亲和性和重复次数,并把结果保存成机器可读格式:
# 使用 CSV 输出,便于保存多次运行的计数结果
perf stat -x, -o perf-baseline.csv -e cycles,instructions -- ./your-program --input sample.dat
# 绑定到同一 CPU 集合,减少调度位置变化带来的噪声
taskset -c 2-3 perf stat -r 5 -x, -e cycles,instructions -- ./your-program --input sample.dat
-r 5 让 perf 重复运行工作负载并汇总结果,-x, 用逗号作为字段分隔符,-o 将统计输出写入文件。这里的重复运行是测量设计,不是质量保证;仍要确保工作负载本身没有随机输入、缓存预热差异或后台任务干扰。
如果程序会改变系统状态,不能简单重复执行同一个命令。可以准备只读输入、隔离输出目录,或让程序提供可重复的基准模式。
用 CPI 把两个计数器变成判断线索
得到计数后,用下面的关系做第一层判断:
# CPI 表示平均每条退休指令消耗的 CPU 周期
CPI = cycles / instructions
CPI 较高通常意味着流水线等待、缓存未命中、分支预测失误或其他微架构停顿更明显;CPI 较低并不自动等于程序更快,因为总指令数、频率、并发度和输入规模也会影响总耗时。更稳妥的比较方式是同时观察:
| 观察项 | 作用 | 不要单独推出的结论 |
|---|---|---|
| cycles | 估计工作负载消耗的处理器周期 | 不能单独代表墙上时间 |
| instructions | 观察退休指令规模 | 不能单独代表每条指令成本 |
| CPI | 把周期与指令规模联系起来 | 不能直接定位具体代码行 |
| branch-misses | 观察分支预测失败线索 | 不能证明唯一瓶颈就是分支 |

把权限和虚拟化边界排除在性能结论之外
perf_events 访问受到内核安全策略约束。Linux 内核文档指出,CAP_PERFMON 可以为非 root 进程提供性能监控相关能力,使用过大的管理员权限并不是首选方案。生产环境还应考虑计数结果中可能包含 CPU 型号、进程名、路径和硬件配置等信息。
# 查看当前 perf 工具和内核环境,记录测量上下文
perf --version
uname -a
# 查看当前进程的 perf_event 相关限制;不同发行版可能有不同权限策略
cat /proc/sys/kernel/perf_event_paranoid
遇到 Permission denied、事件显示 或计数器无法调度时,按“权限—内核配置—CPU/虚拟机能力—事件数量”顺序排查。不要为了让命令有输出就直接使用 root,也不要把权限放宽后的结果与普通权限下的结果无条件混合比较。
一份可复用的最小检查清单
- 先用
perf list确认事件名称和当前环境能力。 - 从
cycles,instructions开始,按问题需要加入分支或缓存事件。 - 固定输入、CPU 集合、重复次数和输出格式,再比较优化前后。
- 同时保存 cycles、instructions、CPI 与墙上时间,避免单指标判断。
- 把权限、虚拟机、内核策略和计数器复用记录在测量说明里。
常见问题
为什么 cycles 和 wall-clock time 不一样?
cycles 是处理器性能计数器的事件数量,wall-clock time 是经过的实际时间,两者受到频率变化、调度、并行线程和系统空闲时间等因素影响。分析 CPU 计算量时看 cycles,评估用户感知延迟时仍要保留实际耗时。
事件太多时为什么会出现缩放或不可用?
硬件 PMU 的可编程计数器数量有限,perf 可能在事件之间分时复用;当某些事件无法同时调度时,结果可能被缩放或直接不可用。减少事件组合并分组测量,通常比盲目添加事件更容易得到可解释结果。
CPI 高是否就说明缓存有问题?
不一定。CPI 是综合指标,缓存等待、分支预测、流水线资源竞争和内存访问都可能影响它。应再选择与假设对应的缓存、分支或停顿事件,并与相同输入下的基线比较。
os/exec Cmd.Cancel 设计超时后的退出动作
- 上一篇
- os/exec Cmd.Cancel 设计超时后的退出动作
- 下一篇
- Import Maps 统一浏览器端依赖别名
-
- 文章 · linux | 3小时前 | 容器 · Linux · Linux mount namespace 挂载传播 bind mount shared mount
- mount namespace 中绑定挂载的传播属性
- 342浏览 收藏
-
- 文章 · linux | 4小时前 |
- ip rule 与多路由表实现策略路由
- 406浏览 收藏
-
- 文章 · linux | 6小时前 |
- nftables 动态集合维护临时封禁地址
- 248浏览 收藏
-
- 文章 · linux | 8小时前 | Linux · journalctl Linux日志 journald systemd-journald Storage=persistent
- journald Storage=persistent 保留重启前日志
- 147浏览 收藏
-
- 文章 · linux | 11小时前 |
- systemd watchdog 监测服务心跳的配置方法
- 482浏览 收藏
-
- 文章 · linux | 23小时前 |
- Linux zram 写回如何在内存与磁盘间平衡
- 373浏览 收藏
-
- 文章 · linux | 1天前 |
- Linux Landlock 怎样限制普通进程访问文件目录
- 151浏览 收藏
-
- 文章 · linux | 1天前 |
- Linux dm-verity 如何校验只读根文件系统
- 190浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 408次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 486次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 494次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 443次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 270次使用
-
- Golang如何编写内存高效及CPU调优的Go结构体
- 2022-12-29 222浏览
-
- 详解golang执行Linuxshell命令完整场景下的使用方法
- 2023-01-07 426浏览
-
- go程序部署到linux上运行的实现方法
- 2023-01-02 387浏览
-
- Linux系统下Go语言开发环境搭建
- 2023-01-07 242浏览
-
- 使用golang获取linux上文件的访问/创建/修改时间
- 2022-12-31 238浏览

