系列文章《深入 perf 第二版理解 CPU 的每一个时钟周期》第 1 篇本系列共 8 篇从最基础的 cycles/instructions 出发逐步深入到微架构、内存层次、多核竞争、系统级干扰、固件层面直至移动 SoC 专题。目标读者有基本 Linux 命令行经验、了解 CPU/内存/进程等基本概念的开发者和性能工程师。“Measure. Don’t tune for speed until you’ve measured.”先测量。没测过别谈优化。—— Rob Pike,Notes on Programming in C1. perf 工具简介上周五晚上 11 点同事发来一条消息新版本上线后 P99 延迟从 5ms 涨到了 20msCPU 利用率没变完全看不出原因。我让他跑了一条命令perfstat-ecycles,instructions ./server_benchmark输出里有一个数字格外扎眼——IPC 只有 0.3。正常情况下这个服务的 IPC 在 1.8 左右。0.3 意味着 CPU 每个时钟周期只完成了 0.3 条指令大量时间在发呆。顺着这个线索我们最终发现新版本引入了一个未排序的大数组遍历导致分支预测命中率从 99% 暴跌到 50%这背后的原理将在第三篇详细展开。一个数字锁定了性能瓶颈的方向。这就是 cycles 和 instructions 的威力——本篇带你彻底搞懂这两个最基础的指标。perf是 Linux 内核自带的性能分析工具基于内核的Performance Counters 子系统perf_event。它通过读取 CPU 硬件中的PMUPerformance Monitoring Unit寄存器来收集性能数据。PMU 是 CPU 芯片内置的硬件模块包含若干可编程计数器通常 6-8 个通用计数器因微架构而异能在不干扰程序正常执行的情况下统计 cycles、cache miss、分支预测失败等微架构事件——你可以把它理解为 CPU 内部的行车记录仪默默记录着每一次操作。[提示]安装 perfperf不是所有发行版默认安装的。Ubuntu/Debiansudo apt install linux-tools-$(uname -r)Fedora/RHELsudo dnf install perf。安装后运行perf --version确认可用。perf有两种核心工作模式开销差异很大计数模式perf stat内核在目标进程每次被调度上 CPU 时恢复 PMU 计数器调度出 CPU 时保存计数器值进程结束时汇总累计值。这种 context-switch 级别的保存/恢复保证了只统计目标进程的事件几乎零开销不触发采样中断采样模式perf recordPMU 计数器每溢出一次就触发一次中断内核保存当前调用栈到 Ring Buffer高频采样下 overhead 约 1-5%[提示]日常使用中先用零开销的perf stat看全局指标判断方向再用perf record精确定位热点——这是性能分析的基本节奏。采样模式的详细原理将在第二篇展开。perf的核心能力统计硬件事件cycles、cache miss、分支预测失败等采样调用栈定位热点函数追踪内核 tracepoint 和用户态 probe实时监控系统级或进程级性能指标perf 与其他性能工具对比在进入perf的具体命令之前先看看它在 Linux 性能工具生态中的位置工具原理适用场景典型开销局限perf硬件 PMU 内核 tracepointCPU 微架构分析、热点定位、全栈性能计数模式 ~0%采样 1-5%需要内核支持部分事件需 rootgprof编译插桩 采样函数级耗时分析5-20%插桩开销需重新编译不支持共享库straceptrace 系统调用拦截系统调用追踪极高每次 syscall 两次上下文切换只能看 syscall无法分析 CPU 内部行为oprofile硬件 PMU旧方案系统级采样1-5%已被perf取代不再积极维护bpftraceeBPF kprobe/uprobe动态追踪、自定义探针取决于探针位置需要较新内核4.15学习曲线陡perf的核心优势是硬件级精度 极低开销它不需要修改程序、不需要重新编译、不拦截系统调用而是直接读取 CPU 硬件计数器。这使它成为性能分析的首选工具——先用perf stat定方向再根据需要引入其他工具深入某一层面。常用命令一览命令用途典型场景perf stat统计硬件/软件事件计数快速获取 IPC、cache miss 率等全局指标perf record采样并记录到perf.data采集热点函数、调用栈perf report分析perf.data文件查看热点函数排名、调用链perf top实时显示系统热点类似top但显示的是函数级 CPU 消耗perf lock分析锁竞争定位 mutex/spinlock 热点perf mem分析内存访问定位 cache miss 的具体内存地址perf list列出可用事件查看当前系统支持哪些 PMU 事件perf annotate指令级热点标注精确到汇编指令的性能分析基本用法示例# 统计某程序的 cycles、instructions、cache miss 等perfstat./my_program# 指定事件统计perfstat-ecycles,instructions,cache-misses,branch-misses ./my_program# 统计已运行进程PID1234持续 10 秒perfstat-p1234sleep10# 采样记录默认按 cycles 采样perf record-g./my_program# -g 表示记录调用栈# 查看采样结果perf report# 实时查看系统热点函数perftop# 只看用户态perftop-U[提示]运行perf通常需要 root 权限或者设置kernel.perf_event_paranoid参数# 查看当前值cat/proc/sys/kernel/perf_event_paranoid# 设为 -1 允许非 root 用户使用全部功能仅在开发/测试环境建议sudosysctlkernel.perf_event_paranoid-1# 持久化重启后生效echokernel.perf_event_paranoid -1|sudotee/etc/sysctl.d/99-perf.conf[注意]perf_event_paranoid-1等同于允许所有用户读取全部 PMU 和 tracepoint 数据不要在生产环境或多租户机器上设置。生产环境建议使用sudo或 Linux capabilitiesCAP_PERFMON内核 5.8做细粒度控制。2. cycles 与 instructions 详解cycles和instructions是 perf 中最基础、最重要的两个硬件事件。理解它们的准确含义是做性能分析的前提。2.1 cycles 详解cycles 是什么cycles统计的是 CPU 核心实际工作的时钟周期数对应 PMU 硬件事件架构PMU 事件名事件编号说明x86UNHALTED_CORE_CYCLESFixed Counter 1IA32_FIXED_CTR1核心未停顿的周期ARM64CPU_CYCLES0x11CPU 活跃周期[提示]固定计数器 vs 通用计数器PMU 中有两类计数器。固定计数器Fixed Counter专门绑定一个事件不可切换——x86 自 Skylake 起有 3 个固定计数器FC0instructions、FC1cycles、FC2ref-cycles不受 DVFS 影响的参考周期第六篇会用到。Ice LakePerfMon v5新增 FC3TOPDOWN.SLOTS微架构 Top-Down 分析的基础第二篇展开更早的微架构只有前 3 个。通用计数器General Purpose Counter可编程监控任意事件数量通常为 4-8 个。固定计数器的好处是不占用通用计数器名额perf stat默认就会同时使用两者。ARM64 PMUv3 没有固定计数器的概念cycles 和 instructions 也占用通用计数器。关于通用计数器的编程方式和 multiplexing 机制将在第二篇详细讨论。关键特性只统计活跃周期CPU 核心时钟信号运行时每个时钟上升沿 cycles 计数器递增一次——不管流水线是否在执行有效指令流水线停顿的周期也计入 cyclesCPU 进入低功耗状态时计数器停止。这里的关键机制是时钟门控clock gating——CPU 不是关机了而是硬件把送给核心的时钟信号掐断了就像把水龙头关上水表PMU自然就不转了。具体来说x86 的HLT指令触发核心时钟门控PMU 停止计数ARM64 的WFIWait For Interrupt核心进入低功耗状态时钟门控PMU 停止计数ARM64 的WFEWait For Event行为更复杂——只有 Event Register 未置位时才暂停核心并停止 PMU 计数如果 Event Register 已置位WFE立即返回不停顿。需要注意的是WFE 暂停时 PMU 是否停止计数在 ARM 架构手册中标注为IMPLEMENTATION DEFINED具体行为取决于芯片实现Cortex-A76/X1 等主流核心确实会停止计数。ARM64 自旋锁使用WFE实现等待这导致锁竞争在perf中隐形将在第五篇详细讨论因此cycles反映的是CPU 干活花了多少个时钟周期而不是墙钟时间过了多少个时钟周期cycles 与频率的关系cycles 的值与 CPU 运行频率直接相关同一段代码在不同频率下运行 频率 1.0 GHz → 每秒 1×10⁹ 个 cycle 频率 2.4 GHz → 每秒 2.4×10⁹ 个 cycle 频率 3.6 GHz → 每秒 3.6×10⁹ 个 cycle 假设某段代码需要 2.4×10⁹ 个 cycles 才能完成 在 1.0 GHz 下: 耗时 2.4×10⁹ ÷ 1.0×10⁹ 2.4 秒 在 2.4 GHz 下: 耗时 2.4×10⁹ ÷ 2.4×10⁹ 1.0 秒 在 3.6 GHz 下: 耗时 2.4×10⁹ ÷ 3.6×10⁹ ≈ 0.67 秒[注意]现代 CPU 支持动态调频DVFS频率可能在运行过程中变化。如果需要可重复的基准测试建议锁定频率# 查看当前频率策略cat/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor# 锁定为最高频率cpupower 需安装Ubuntu/Debian sudo apt install linux-tools-commonFedora sudo dnf install kernel-toolssudocpupower frequency-set-gperformance2.2 instructions 详解instructions 是什么instructions统计 CPU 成功执行retired的指令数对应 PMU 事件架构PMU 事件名事件编号说明x86INST_RETIRED.ANYFixed Counter 0IA32_FIXED_CTR0成功退休的指令数ARM64INST_RETIRED0x08成功退休的指令数关键特性只统计 retired 指令现代 CPU 采用推测执行speculative executionCPU 会在分支结果确定之前猜测执行一条路径上的指令。如果猜错了这些指令会被丢弃squash。打个比方你开车到路口导航还没算出路线但你凭直觉先往左转了。如果导航最终显示左转——恭喜你节省了等待时间如果显示直行——你得倒回路口重来。CPU 的推测执行就是这个道理赌对了加速流水线赌错了白做一轮。分支预测的命中率直接影响 CPU 效率这将是第三篇的核心主题。Retired 指令最终确认正确并提交结果的指令 →计入instructionsSquashed 指令推测执行后被丢弃的指令 →不计入instructions这意味着即使 CPU 实际执行了大量推测指令instructions只反映有效工作量。与频率无关同一段代码在不同频率下运行instructions的值是一样的——需要执行的指令数由代码逻辑决定与频率无关。变化的是cycles和墙钟时间频率越高单位时间内完成的 cycles 越多程序越快结束。在同一微架构上相同代码的 cycles 数通常也是稳定的cycles计的是核心时钟周期数除非频率变化导致内存访问的相对延迟改变DDR 延迟是固定纳秒数CPU 频率越高等内存的 cycles 越多。为什么会这样因为 DDR 内存的访问延迟是以纳秒为单位的物理常数~50-80 ns与 CPU 频率无关。CPU 频率越高同样 80 ns 的等待需要消耗越多的 cycles1 GHz 下是 80 cycles3 GHz 下就是 240 cycles。打个比方你是一个越来越快的厨师CPU 提频但传菜窗口的速度没变DDR 延迟固定。你切菜快了一倍等菜的时间占比就从 30% 变成了 50%——你虽然更快了但越来越多的时间花在等食材上。反映到 perf 数据上就是 CPU 频率翻倍后 cycles 并没有减半因为多出的 cycles 都在等内存。这种CPU 越快、等内存的比例越高的现象背后是一个更宏观的趋势memory wall内存墙——过去几十年 CPU 运算速度的提升远快于内存延迟的改善Wulf McKee, 1995导致内存访问日益成为性能瓶颈。第四篇将详细讨论。[提示]试一试在你的机器上分别运行下面两条命令对比 IPC 差异perfstatls/tmp perfstatddif/dev/zeroof/dev/nullbs4kcount100000ls涉及大量 syscall 和 I/O 等待IPC 通常不到 1.0而dd是纯数据拷贝IPC 可能在 1.5-2.5 之间。同一台机器两个程序的 IPC 能差 2-3 倍——这就是 IPC 的诊断价值。2.3 IPC 与 CPI 展开计算IPCInstructions Per Cycle和 CPICycles Per Instruction是衡量 CPU 效率的核心指标两者互为倒数。定义IPC instructions ÷ cycles 每个周期完成多少条指令 CPI cycles ÷ instructions 每条指令花多少个周期完整计算示例假设perf stat输出如下Performance counter stats for ./my_program: 3,000,000,000 cycles 1,500,000,000 instructions # 0.50 insn per cycle 1.250325718 seconds time elapsed第一步计算 IPCIPC instructions ÷ cycles 1,500,000,000 ÷ 3,000,000,000 1.5 ÷ 3.0 0.5第二步计算 CPICPI cycles ÷ instructions 3,000,000,000 ÷ 1,500,000,000 3.0 ÷ 1.5 2.0也可以直接用 IPC 求CPI 1 ÷ IPC 1 ÷ 0.5 2.0第三步解读含义指标值含义IPC0.5平均每个时钟周期只完成 0.5 条指令CPI2.0平均每条指令需要 2 个时钟周期才能完成对于现代超标量CPU 大核——所谓超标量就是 CPU 每个时钟周期能同时处理多条指令峰值 IPC 通常在 4-8 之间取决于 decode/retire 宽度——x86 Golden Cove 的 retire 宽度为 6ARM Cortex-X4 的 retire 宽度为 8IPC 0.5 说明存在严重的流水线停顿。CPU 大量时间在等待而非干活——可能的原因包括 cache miss第四篇、分支预测失败第三篇、内存延迟等。[注意]小核与大核的峰值 IPC 差异巨大。例如 Cortex-A55 是顺序执行的双发射核心按程序顺序取指和发射decode/issue 宽度为 2峰值 IPC 约 2而 Cortex-A76 是 4 发射宽乱序核心峰值 IPC 约 4。IPC 1.0 在 A55 上已经是高效率在 A76 上则意味着只发挥了 1/4 的能力。第四步估算执行时间与优化空间假设 CPU 运行在 2.4 GHz当前执行时间 cycles ÷ 频率 3,000,000,000 ÷ 2,400,000,000 3.0 ÷ 2.4 1.25 秒如果通过优化减少 cache miss、改善分支预测等将 IPC 提升到 2.0优化后 cycles instructions ÷ 新 IPC 1,500,000,000 ÷ 2.0 750,000,000 优化后执行时间 优化后 cycles ÷ 频率 750,000,000 ÷ 2,400,000,000 0.75 ÷ 2.4 0.3125 秒加速比 原时间 ÷ 优化后时间 1.25 ÷ 0.3125 4.0 倍也就是说IPC 从 0.5 提升到 2.04 倍执行时间相应缩短到 1/4 ——提速 4 倍。IPC 比较的注意事项[注意]IPC 不能跨不同微架构或不同频率直接比较。不同微架构Cortex-A55顺序双发射decode/issue 宽度 2峰值 IPC 约 2和 Cortex-A76宽乱序执行峰值 IPC 约 4的 IPC 没有可比性。IPC 1.0 在 A55 上已经发挥了一半峰值在 A76 上则意味着效率较低。SIMD 指令的影响使用 NEON/SVE/AVX 等 SIMD 指令后instructions会大幅减少。举个例子——用标量指令对 4 个 float 求和需要 4 条faddinstructions 4用 NEON 的faddp一条搞定instructions 1。此时 IPC 可能从 1.0 降到 0.25看起来变差了但实际吞吐量提升了 4 倍。所以优化前后 IPC 的比较必须结合instructions的变化一起看。正确做法在同一微架构、同一频率下比较优化前后的 IPC 变化同时关注instructions是否因 SIMD 化而大幅减少。3. 三种典型瓶颈的 perf stat 特征等一下——IPC 低就一定是 cache miss 吗不一定。不同类型的性能瓶颈在perf stat输出上有截然不同的指纹。学会读这张指纹是从数字到诊断的关键一步。下面用一条命令采集关键指标对比三种典型场景perfstat-ecycles,instructions,cache-misses,branch-misses,task-clock ./program指标CPU bound计算密集Memory bound内存密集I/O boundI/O 密集IPC2.0-4.0高效0.2-0.8频繁停顿不定在 CPU 上时可能正常cache-misses / cache-references低 1%高 5%中等branch-misses低 1%低-中低task-clock vs elapsed接近 1:1接近 1:1task-clock 远小于 elapsed见下方说明瓶颈位置CPU 流水线内存子系统第四篇详解进程被挂起等 I/O第六篇详解IPC 无参考意义task-clock是perf stat输出中容易被忽略的一个软件事件它统计的是进程实际占用 CPU 的时间单位 ms而elapsed是墙钟时间。对于单线程程序两者的差值就是进程不在 CPU 上的时间。举个例子一个程序跑了 10 秒elapsed但task-clock只有 2000 ms说明有 8 秒它在睡觉——被 I/O 阻塞、等锁、或者被调度器换出去了。所以task-clock / elapsed的比值是区分 CPU bound 和 I/O bound 最快的一招。正因为 I/O bound 的进程大部分时间不在 CPU 上它的 IPC 反映的只是短暂上 CPU 期间的效率参考意义不大——关键信号是task-clock elapsed。[注意]cache-misses跨架构含义不同。在 Intel CPU 上perf stat -e cache-misses映射为LLCLast Level Cachemiss而在部分 ARM64 平台上它可能映射为L1D cache miss——两者差了好几个数量级。跨架构比较 cache-misses 数值没有意义。如需精确控制应使用明确的事件名如LLC-load-misses或原始 PMU 事件编号第二篇详解。[注意]对于多线程程序task-clock是所有线程 CPU 时间的累加值可能大于elapsed。例如 4 个线程各跑 10 秒task-clock≈ 40000 mselapsed≈ 10 秒。此时task-clock / elapsed ≈ 4.0表示平均用了 4 个核心。[提示]试一试分别运行一个死循环算 Fibonacci、一个随机访问大数组、一个频繁读写文件的程序用perf stat采集上述 5 个指标看看是否符合表格中的模式。4. 避坑指南4.1 Multiplexing 导致数据不准等一下——PMU 通用计数器只有 4-8 个因微架构而异我同时监控 20 个事件怎么办好问题。内核的解决方案是 multiplexing。PMU 通用计数器数量有限通常 4-8 个。当你用-e同时监控超过计数器数量的事件时内核会在多个事件之间分时复用multiplexing——把事件分成几组轮流上计数器。具体机制内核每隔一个 tick 切换一次事件组切换频率取决于内核配置的CONFIG_HZHZ1000 时约 1 msHZ250 时约 4 ms。假设你监控 12 个事件但只有 4 个通用计数器内核把它们分成 3 组每组轮流采集 1/3 的时间。最终结果 采集到的值 × (1 / 采集时间占比)。比如某事件在 2/3 时间段内采集到 800 次估算值就是 800 × (3/2) 1200。问题在于如果程序行为不均匀前半段 cache miss 密集后半段几乎没有恰好只采集到了好的那段时间估算值就会偏低。# 监控 20 个事件远超计数器数量perfstat-ecycles,instructions,cache-references,cache-misses,\branch-instructions,branch-misses,bus-cycles,ref-cycles,\L1-dcache-loads,L1-dcache-load-misses,L1-dcache-stores,\L1-icache-load-misses,dTLB-loads,dTLB-load-misses,\iTLB-loads,iTLB-load-misses,context-switches,cpu-migrations,\page-faults,stalled-cycles-frontend ./my_program输出中会出现(xx.xx%)标记表示该事件实际只采集了部分时间1,234,567 cache-misses (66.67%) # ← 只采集了 2/3 时间[注意]当你看到(xx%)低于 100% 时数据是估算值可能有偏差。关键分析建议一次只监控 4-6 个事件分多次运行采集不同事件组。在 x86 上cycles和instructions使用固定计数器Fixed Counter不受 multiplexing 影响但 ARM64 PMUv3 没有固定计数器cycles和instructions也占用通用计数器事件过多时同样可能被 multiplex。4.2 虚拟机中 PMU 不可用多数虚拟化平台默认不暴露 PMU 给虚拟机。在 VM 中运行perf stat可能只得到软件事件context-switches、page-faults硬件事件全部显示not supported。解决方案KVM宿主机配置-cpu host透传 PMU云服务器部分云厂商如 AWS bare-metal 实例支持 PMU 访问容器共享宿主机内核perf通常可用但需要CAP_SYS_ADMIN或perf_event_paranoid设置5. 实用技巧# 多次运行取均值减少单次运行的随机波动推荐 3-5 次perfstat-r5./my_program# 去掉千位分隔符便于脚本解析perfstat--no-big-num-ecycles,instructions ./my_program# 输出 CSV 格式直接喂给 awk/pandasperfstat-x,-ecycles,instructions ./my_program# 只统计用户态事件排除内核开销干扰perfstat-ecycles:u,instructions:u ./my_program# 同时监控多个进程perfstat-p1234,5678sleep10[提示]-r 5是最容易被忽略也最实用的参数。单次运行的 cycles 可能波动 5-10%受调度、中断等影响取 5 次均值后方差显著降低。这也是开篇故事中我们能快速定位 IPC 异常的前提——先确认数据是稳定可复现的。6. 从 perf stat 到瓶颈定位诊断工作流拿到perf stat输出后按以下决策树判断瓶颈方向perf stat 输出 │ ├─ task-clock 远小于 elapsed time │ └─ 是 → Off-CPU 瓶颈I/O/锁等待/被抢占 │ → 下一步perf sched / offcputimeBCC 工具第六篇 │ ├─ IPC 1.0 │ ├─ cache-misses 高→ 内存子系统瓶颈 │ │ → 下一步perf mem / perf c2c第四篇 │ ├─ branch-misses 高→ 分支预测失败 │ │ → 下一步perf record 热点分析第三篇 │ └─ 都不高→ 可能是指令延迟/依赖链/前端瓶颈取指或解码阶段供不上指令 │ → 下一步perf stat -e 微架构事件第二篇 │ ├─ IPC 1.0-2.0 │ └─ 有优化空间 → 用 -e 细化事件定位具体停顿来源 │ → 下一步perf stat -e 微架构事件第二篇 │ └─ IPC 2.0 └─ CPU 效率良好 如果仍然觉得慢 → 检查是否是算法复杂度问题instructions 太多7. 速查表IPC 判断标准现代大核参考值IPC 范围评价典型原因下一步动作 2.0优秀CPU 流水线高效利用如需继续优化关注 instructions 减少算法优化1.0 - 2.0一般存在一定停顿用-e细化事件定位具体停顿来源0.5 - 1.0较差频繁 cache miss 或分支失败perf record采样定位热点 0.5严重问题大量内存等待或流水线阻塞优先检查 cache-misses 和内存访问模式[注意]以上参考值适用于现代大核Cortex-A76/X1 级别、x86 Skylake 及以后。小核如 Cortex-A55峰值 IPC 只有约 2判断标准需要减半。perf stat 常用参数速查参数用途示例-e指定事件-e cycles,instructions,cache-misses-r N运行 N 次取均值-r 5-p PID监控指定进程-p 1234-a系统级监控所有 CPU-a sleep 5-x SEPCSV 格式输出-x,--no-big-num去掉千位逗号便于脚本解析-I ms每隔 N 毫秒输出一次-I 1000每秒:u/:k只统计用户态/内核态-e cycles:u8. FAQQ1perf stat 的 cycles 和time elapsed是什么关系cycles是 CPU 核心实际工作的时钟周期数time elapsed是墙钟时间。两者的关系time elapsed ≈ cycles / 频率单核情况下。如果time elapsed远大于cycles / 频率说明进程大量时间不在 CPU 上运行Off-CPU应排查 I/O 等待或锁竞争。Q2为什么 perf stat 输出中 instructions 是 0常见原因(1) 程序太短还没来得及执行几条指令就结束了——试着给程序加大负载或循环次数(2) 在虚拟机中 PMU 不可用所有硬件事件都是 0 或not supported——参见上面的虚拟机章节。Q3IPC 超过了微架构的理论峰值是 perf 测量错误吗不一定是错误。最常见的原因是指令融合macro-fusionx86 CPU 会把特定的指令对如CMPJCC在解码阶段合并为一条微操作但instructions仍按两条计数。这使得instructions / cycles可以超过 decode 宽度。另外multiplexing 导致的估算误差也可能产生略微偏高的 IPC。注意SIMD 指令虽然一条抵多条标量操作但它本身也只计为 1 条 instruction——所以 SIMD 化会降低instructions 和 IPC不会让 IPC 超过峰值。Q4perf stat和time命令的 real/user/sys 有什么区别time的usersys≈perf stat的task-clockCPU 上的执行时间real≈time elapsed墙钟时间。perf stat额外提供了 cycles、instructions、IPC 等硬件级指标这是time无法给出的——这也是我们选择perf作为性能分析首选工具的原因。Q5多线程程序的 IPC 怎么看perf stat默认统计的是目标进程的所有线程在所有 CPU 上的累加值。累加的 IPC 反映的是所有核心的平均效率但可能掩盖个别核心的瓶颈——比如 3 个线程 IPC2.0 和 1 个线程 IPC0.3 的平均值仍然看起来还行。如果想看单个线程可以用-t TID指定线程 ID如果想看每个 CPU 核心的独立数据使用-Aper-CPU模式。多核场景下的 IPC 解读将在第五篇深入讨论。还记得开头的故事吗IPC 从 1.8 跌到 0.3一个数字就锁定了分支预测失败的方向。perf stat输出中的每个数字都不是摆设——cycles 告诉你 CPU 花了多少时间instructions 告诉你干了多少活IPC 告诉你效率高不高cache-misses 告诉你卡在哪里。学会读这些数字就是性能分析的第一步。下一篇预告perf list显示了 20 多个通用事件——但你的 CPU 里其实藏着几百个隐藏计数器能精确追踪到L2 Cache 因预取导致的未命中这种粒度。怎么访问它们下一篇揭晓。