深入linux c/c++调试工具之perf

📅 2026/7/8 4:12:04
深入linux c/c++调试工具之perf
目录一、前言-perf 工具简介二、使用场景——何时使用 perf1、程序 CPU 占用高不知道热点在哪2、程序「感觉慢」但 strace 看不出 syscall 瓶颈3、优化前后效果验证4、多线程 / 锁竞争 / 上下文切换问题5、缓存未命中、分支预测失败深度优化6、内核 用户态联合分析7、C/C 程序无源码时的性能摸底三、核心原理——工作原理深度解析3.1 基本架构3.2 两种主要工作模式1计数模式perf stat2采样模式perf record / perf top3.3 事件来源3.4 调用栈如何获得-g 的关键四、命令参数——常用选项详解五、使用实战——实际案例分析六、常见问题——疑难解答七、总结——要点回顾一、前言-perf 工具简介perf 是 Linux 内核自带的 性能分析工具基于内核的 perf_events 子系统可采集 CPU 周期、指令、缓存缺失、分支预测失败、系统调用、函数调用链等事件用于 定位热点函数、分析 CPU 瓶颈、排查性能退化。二、使用场景——何时使用 perf1、程序 CPU 占用高不知道热点在哪典型现象:top显示进程 CPU 90%但不知道哪个函数耗 CPU多线程程序某个线程跑满。2、程序「感觉慢」但 strace 看不出 syscall 瓶颈典型现象strace-c显示 syscall 总耗时不高,程序仍然慢。3、优化前后效果验证典型现象改了算法/数据结构想量化提升需要对比两个版本的 CPU 分布。4、多线程 / 锁竞争 / 上下文切换问题典型现象CPU 不高但整体吞吐低怀疑 spinlock、futex、线程切换过多。5、缓存未命中、分支预测失败深度优化典型现象算法已优化性能仍不理想怀疑 cache miss、false sharing。6、内核 用户态联合分析典型现象驱动、网络、存储程序慢不确定时间耗在用户态还是内核态。7、C/C 程序无源码时的性能摸底典型现象第三方.so/ 闭源二进制慢只有符号表或部分符号。三、核心原理——工作原理深度解析perf 的核心是 Linux 内核的 perf_events 子系统在内核中注册性能监控事件按计数或采样方式采集数据写入 perf.data再由用户态工具解析展示。3.1 基本架构3.2 两种主要工作模式1计数模式perf stat对指定事件 全程计数输出汇总cycles、instructions、cache-misses 等低开销适合看整体指标2采样模式perf record / perf top每隔 N 个事件如每 4000 个 cycles 采一次样记录PC程序计数器、进程、线程、调用栈统计哪些函数出现频率高 → 热点3.3 事件来源类型说明示例HardwarePMUCPU 硬件性能计数器cycles, instructions, cache-missesSoftware内核软件事件context-switches, page-faultsTracepoint内核静态跟踪点syscalls:sys_enter_open, sched:sched_switchProbe动态探针kprobe/uprobe指定函数入口/返回3.4 调用栈如何获得-g 的关键C/C 程序要看到 函数名 而非地址需要编译时加-g保留 DWARF 调试信息perf record 加-g采集 call graph系统允许读取符号/proc/sys/kernel/perf_event_paranoid四、命令参数——常用选项详解命令用法 usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS]参数说明annotate读取perf.data由perf record生成并显示 带热点标注的源码/汇编archive根据perf.data中的 build-id 打包目标文件便于 离线分析bench基准测试套件 的通用框架buildid-cache管理 build-id 缓存buildid-list列出perf.data文件中的 build-idc2c共享数据 C2C/HITM 分析器分析多核缓存行竞争、伪共享等config读取/设置 perf 配置文件 中的变量data与 perf.data 数据文件 相关的处理操作diff读取多个perf.data显示 差异性能报告优化前后对比evlist列出perf.data中记录的 事件名称ftrace内核 ftrace 功能的简易封装inject过滤并 向事件流注入额外信息kallsyms在 运行中的内核 里搜索符号kmem跟踪/测量 内核内存 相关特性kvm跟踪/测量 KVM 客户机Guest OSlist列出所有可用的 符号化事件类型lock分析 锁相关事件锁竞争等mem分析 内存访问 行为record运行命令并将性能数据 记录到 perf.datareport读取perf.data并 显示性能分析报告sched跟踪/测量 调度器 特性延迟等script读取perf.data并以 脚本/文本形式 输出跟踪内容stat运行命令并收集 性能计数器统计test运行 自检/健全性测试timechart将负载运行期间的 系统整体行为可视化时间线图表top系统性能实时分析 工具类似 top但看热点version显示 perf 可执行文件版本probe定义新的 动态跟踪点kprobe/uprobe 等trace受 strace 启发 的工具syscall 跟踪开销通常低于 strace五、使用实战——实际案例分析代码实例perf_demo.c#include stdio.h #include stdlib.h #include string.h #include unistd.h #include fcntl.h #include math.h /* 热点1CPU 密集 */ static volatile double sink; static void cpu_hot(void) { double s 0; int i 0; for (i 0; i 50000000; i) s sin(i * 0.000001); sink s; } /* 热点2内存拷贝 */ static void mem_hot(void) { int i 0; char *a malloc(4 * 1024 * 1024); char *b malloc(4 * 1024 * 1024); if (!a || !b) return; for (i 0; i 100; i) memcpy(b, a, 4 * 1024 * 1024); free(a); free(b); } /* 非热点sleep IO 等待 */ static void io_wait(void) { sleep(1); } int main(void) { printf(perf demo pid%d\n, getpid()); cpu_hot(); mem_hot(); io_wait(); printf(done, sink%f\n, (double)sink); return 0; }1、perf stat——整体性能画像perf stat -d ./perf_demosleep(1)期间 几乎不占 cyclesperf stat 主要统计运行态大量 cycles 在 cpu_hot mem_hot下一步 →perf record -g看具体函2、perf record report——定位热点函数perf record -g -F 997 ./perf_demoperf report --stdio -n --sort dso,symbol | head -30阶段现象对应源码热点1cpu_hotsin占 ~75%cpu_hot()循环热点2memcpy占 ~18%mem_hot()百次 4MB 拷贝非热点sleep几乎不出现IO 等待不占 CPU3、perf top——实时看谁在跑./perf_demo perf top -p $! -g运行初期sin、cpu_hot条目飙升随后memcpy占比上升sleep阶段 perf top 样本几乎不4、perf annotate——热点到源码行perf record -g ./perf_demoperf annotate -s cpu_hot精确到 哪一行汇编/源码 最耗 CPU指导优化如减少sin调用、查表法。六、常见问题——疑难解答1、perf report 只显示地址没有函数名原因编译未加-g二进制被 strip权限/paranoid 限制2、提示 Permission denied / Access denied原因kernel.perf_event_paranoid过严或需 root 采系统级事件。3、调用栈不完整或显示 [unknown]原因栈回溯方式不合适frame pointer 被优化掉缺少-g或-fno-omit-frame-pointer4、perf 结果「看起来」和 top 不一致原因perf 默认采 cyclestop 看 %CPU多线程、采样频率、off-CPU 时间影响七、总结——要点回顾perf 跟踪的是 CPU 性能事件和热点函数回答「时间花在哪些函数/指令上」而不是「发起了哪些 syscall」。原理是 perf_events 采样/计数开销通常低于 ptrace 型 strace适合 短时性能分析但仍不建议 7×24 全开。C/C 分析三板斧perf stat ./app # 整体指标perf record -g ./app # 录热点perf report # 看报告务必-g编译 perf record -g必要时-fno-omit-frame-pointer否则调用栈残缺。与 strace 配合最高效 strace 排除 syscall/IO 问题 → perf 定位 CPU 热点 → gdb 深入具体函数。