文档目录

这是把前面所有理论落地到实践的工具箱。没有测量,你的一切优化都是盲人摸象——你以为快了,实际上可能更慢了;你以为瓶颈在 A,实际上在 B。

我们不讲空话,直接上**硬件性能计数器(PMC)和火焰图(Flamegraph)**这两把“屠龙刀”。


1. 性能测量的核心工具:硬件性能计数器(PMC)

PMC(Performance Monitoring Counters) 是 CPU 内部的硬件计数器,可以精确记录各种微架构事件,如:

  • Cache Miss(L1/L2/L3 未命中次数)
  • TLB Miss(地址翻译未命中次数)
  • 分支预测失败(Branch Misprediction)
  • CPU 周期数(Cycles)
  • 指令执行数(Instructions)
  • 内存带宽(Memory Bandwidth)

这些计数器是纯硬件的,不依赖操作系统采样,几乎没有性能开销(<1%)。

硬件实现

[CPU 核心]
    │
    ├── 执行单元(ALU)
    │   └── 计数器:指令执行数、周期数
    │
    ├── 缓存系统(L1/L2/L3)
    │   └── 计数器:Cache Miss、Cache Hit、缓存行传输
    │
    ├── MMU / TLB
    │   └── 计数器:TLB Miss
    │
    └── 分支预测器
        └── 计数器:分支预测成功/失败

2. Linux perf:最强大的硬件性能分析工具

perf 是 Linux 内核自带的性能分析工具,封装了 CPU 的 PMC,可以精确测量程序的硬件行为。

常用命令速查

### 1. 统计程序的硬件事件(最常用)
perf stat ./your_program

### 输出示例:
### 1,234,567,890  cycles               # CPU 周期数
### 5,678,901,234  instructions         # 指令数
### 123,456,789    cache-misses         # Cache Miss
### 987,654,321    L1-dcache-load-misses # L1 数据缓存未命中
### 0.8  IPC (instructions per cycle)   # 每个周期执行的指令数(越高越好)

### 2. 统计特定事件
perf stat -e cache-misses,TLB-misses,context-switches ./your_program

### 3. 采样分析(找出热点函数)
perf record -g ./your_program   # 记录采样数据
perf report                    # 查看报告(按 CPU 时间排序)

### 4. 查看所有可用事件
perf list

perf stat 的“黄金指标”

指标 含义 健康范围 异常指标
IPC 每周期指令数 > 1.0 < 0.5 说明大量停顿
Cache Miss Rate L1/L2/L3 未命中率 L1 < 5%, L2 < 10%, L3 < 20% 超出范围说明内存访问模式差
TLB Miss Rate TLB 未命中率 < 1% 超出范围说明页表压力大,考虑大页
Branch Misprediction 分支预测失败率 < 5% 超出范围说明分支不可预测
Context Switches 上下文切换次数 越低越好 高说明锁竞争严重

3. 火焰图(Flamegraph):可视化性能瓶颈

perf record 可以生成调用栈采样数据,Brendan Gregg 发明了 火焰图(Flamegraph) 来可视化这些数据。

生成火焰图

### 1. 采样 60 秒
perf record -F 99 -g ./your_program  # -F 99 = 每秒 99 次采样

### 2. 生成火焰图
perf script | ./FlameGraph/stackcollapse-perf.pl | ./FlameGraph/flamegraph.pl > flame.svg

### 3. 在浏览器中打开 flame.svg

火焰图的读法

纵轴:调用栈深度(从下到上)
横轴:CPU 时间占比(宽度越大,占用 CPU 越多)

  ▲
  │  [memcpy]   ← 横向越宽,说明这里消耗 CPU 时间越多
  │  [process]  ← 你的业务逻辑
  │  [main]     ← 程序入口
  │
  └─────────────────────────────────→

关键看"平顶山"(横向宽度大):说明该函数是性能瓶颈!

典型瓶颈定位

火焰图特征 对应问题 解决方案
memcpy 宽大 大量内存拷贝 引入零拷贝(mmap / sendfile)
malloc / free 宽大 频繁内存分配 使用内存池 / 对象池
futex / pthread_mutex_lock 宽大 锁竞争严重 改为无锁数据结构
syscall / entry_SYSCALL_64 宽大 系统调用频繁 减少系统调用(批量 / io_uring)
__d_lookup / ext4_* 宽大 文件系统 I/O 使用 Page Cache / 缓存文件

4. 微观测量:微基准测试(Microbenchmarking)

用于精确测量单个操作的耗时(如一次 CAS、一次内存分配、一次函数调用)。

工具:Google Benchmark

#include <benchmark/benchmark.h>
#include <atomic>

std::atomic<int> counter{0};

// 测量无锁自增的耗时
static void BM_AtomicIncrement(benchmark::State& state) {
    for (auto _ : state) {
        counter.fetch_add(1, std::memory_order_relaxed);
    }
}
BENCHMARK(BM_AtomicIncrement);

// 测量 Mutex 锁的耗时
static void BM_MutexLock(benchmark::State& state) {
    std::mutex mtx;
    for (auto _ : state) {
        mtx.lock();
        mtx.unlock();
    }
}
BENCHMARK(BM_MutexLock);

BENCHMARK_MAIN();

运行输出:

Benchmark                  Time (ns)    CPU (ns)
BM_AtomicIncrement         5.2         5.2      ← 一次 CAS 约 5ns
BM_MutexLock               45.3        45.3     ← 一次 lock/unlock 约 45ns

硬件视角:

  • 微基准测试能让单个操作的硬件开销暴露出来(如 CAS 的缓存行 RFO 延迟)。
  • 如果测试结果与理论预期不符,说明有隐藏的硬件行为(如伪共享、TLB Miss)。

5. 宏观测量:系统级 trace(ftrace / bpftrace)

用于追踪操作系统级别的事件,如:

  • 调度器事件:线程被抢占、唤醒、迁移。
  • 中断处理:硬中断、软中断(SoftIRQ)。
  • 文件系统操作:read / write / fsync 的延迟。
  • 网络事件:收包延迟、丢包。

工具:bpftrace(动态追踪)

### 跟踪所有系统调用
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_* { printf("%s\n", probe); }'

### 跟踪文件读写延迟
sudo bpftrace -e 'kprobe:vfs_read { @start[tid] = nsecs; } 
                  kretprobe:vfs_read /@start[tid]/ { 
                      @latency = hist(nsecs - @start[tid]); 
                      delete(@start[tid]); 
                  }'

硬件视角

  • ftrace/bpftrace 让你看到内核态的瓶颈(如页面回收、文件系统锁、调度器延迟)。
  • 如果你的用户态程序已经极致优化,但整体吞吐上不去,问题往往在内核。

6. 笔记存档:性能测量核心概念速查

工具 测量对象 精度 学习曲线
perf stat 硬件计数器(Cache Miss、TLB Miss、IPC) 硬件精确 低
perf record + flamegraph CPU 热点函数 + 调用栈 采样(统计) 中
Google Benchmark 单操作延迟(微基准测试) 纳秒级 低
bpftrace / ftrace 内核事件(系统调用、调度、IO) 微秒级 高
Intel VTune / AMD uProf 全面的硬件性能分析(含微架构细节) 硬件精确 高

本节关键词:PMC、perf、火焰图、微基准测试、bpftrace、IPC、Cache Miss、TLB Miss。 与前期知识的关联:

  • 伪共享检测:用 perf stat -e cache-misses 定位缓存行乒乓。
  • 内存分配器:用火焰图看 malloc / free 占比。
  • 无锁队列验证:用微基准测试对比 CAS 自旋 vs Mutex 的延迟。
  • NUMA 检测:用 perf stat -e node-loads,node-load-misses 看跨节点访问。