news 2026/9/28 21:23:40

3、热点函数定位:perf工具使用、火焰图生成与解读、采样原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
3、热点函数定位:perf工具使用、火焰图生成与解读、采样原理

3.1 采样原理:为什么 perf 能“猜”得这么准?

perf 的核心机制是采样。它不是一条一条指令去数,而是每隔一段时间“咔嚓”拍一张快照。比如每 1 毫秒中断一次 CPU,看看当前在跑什么函数。跑得越多的函数,被拍到的概率就越大。

这就像你站在路口数车——你不需要每辆车都记下来,每隔 10 秒看一眼,哪个方向车多,一目了然。

关键点:采样频率决定了精度。频率太高,系统开销大;频率太低,可能漏掉热点。我个人建议,生产环境用 99Hz 或 199Hz,开发环境可以开到 1000Hz。

我曾经在一个数据库项目里遇到过,采样频率设成 49Hz,结果热点函数完全没抓到。后来改成 99Hz,问题立刻暴露——一个锁竞争函数占了 40% 的 CPU。你说这坑踩得值不值?

3.2 perf 工具实战:从安装到出结果

perf 是 Linux 内核自带的工具,大部分发行版需要单独安装:

# Ubuntu/Debian sudo apt install linux-tools-common linux-tools-$(uname -r) # CentOS/RHEL sudo yum install perf # 验证安装 perf --version

安装完,咱们直接上手。假设你要分析一个正在运行的进程,PID 是 12345:

# 采样 10 秒,频率 99Hz sudo perf record -F 99 -p 12345 -g -- sleep 10 # 查看结果 sudo perf report -g

这里-g是关键——它开启调用链采样。没有它,你只能看到函数名,看不到谁调了谁。我刚开始用 perf 时,经常忘了加-g,结果分析半天发现信息不够,还得重跑。嗯,这算是个小教训。

小技巧:如果不想 attach 到进程,可以直接跑命令:perf record -F 99 -g -- ./your_program。适合压测场景。

3.3 火焰图生成:把数据变成“看得见”的热点

perf report 的输出是文本,虽然能看,但不够直观。我强烈推荐用火焰图。它把调用栈堆叠起来,宽度代表 CPU 占用率,一眼就能看出哪个函数最“胖”。

生成火焰图需要 Brendan Gregg 的脚本:

# 下载脚本 git clone https://github.com/brendangregg/FlameGraph.git # 生成折叠栈 perf script > out.perf ./FlameGraph/stackcollapse-perf.pl out.perf > out.folded # 生成 SVG 火焰图 ./FlameGraph/flamegraph.pl out.folded > flame.svg

打开 flame.svg,你会看到类似这样的结构:

你看这个图,compute_hash()占了 35%,明显是热点。再往下看,sha256()和memcpy()是它的子函数。这说明什么?要么是哈希算法太慢,要么是内存拷贝太多。

注意:火焰图不是万能的。它只能告诉你“CPU 花在哪”,不能告诉你“为什么花在这”。比如一个函数频繁被调用但每次执行很快,火焰图上也会显得很宽。这时候需要结合源码分析。

3.4 火焰图解读:三个常见模式

我总结了几种常见模式,你对照着看,基本能快速定位问题:

模式火焰图特征可能原因优化方向
平顶山顶部有一个很宽的矩形,底部窄函数自身计算量大(如加密、压缩)算法优化、硬件加速、缓存结果
尖塔群很多细长的矩形,高度相似频繁调用小函数(如日志、格式化)减少调用次数、内联、批量处理
深井调用链很深,每一层都很窄多层抽象、虚函数、回调嵌套减少抽象层次、使用直接调用

我记得有一次,看到一个“尖塔群”模式的火焰图,全是std::string的拷贝构造。后来发现是代码里大量传值而不是传引用。改完之后,性能提升了 30%。

3.5 避坑指南:我踩过的几个坑

perf 和火焰图虽然好用,但有几个坑你得注意:

  • 采样周期太短:我曾经只采样 1 秒,结果热点函数没出现。建议至少采样 10 秒,或者跑完一个完整业务周期。
  • 忘记加 -g:没有调用链信息,火焰图就是一堆孤立的函数名,根本看不出调用关系。
  • 内核符号未加载:如果看到大量[unknown],说明内核符号没加载。加-k参数或者安装kernel-debuginfo包。
  • JIT 代码不显示:Java、Node.js 等 JIT 语言,需要额外配置才能看到热点。比如 Java 要加-XX:+PreserveFramePointer。

我的习惯:每次优化前,先跑一次 perf 生成火焰图,保存为基线。优化后再跑一次,对比两张图。这样能直观看到优化效果。

3.6 实战案例:一个真实的热点定位过程

最后,我分享一个真实案例。某次线上服务 CPU 飙到 90%,我按以下步骤排查:

  1. perf record:采样 30 秒,频率 99Hz,带调用链。
  2. 生成火焰图:发现json_parse()占了 45% 的 CPU。
  3. 放大查看:火焰图显示json_parse()内部大量调用strlen()和malloc()。
  4. 源码分析:发现每次解析 JSON 字段时,都重新分配内存并拷贝字符串。
  5. 优化:改用零拷贝解析库,预分配缓冲区。
  6. 验证:再次 perf 采样,json_parse()降到 12%,整体 CPU 降到 40%。

整个过程不到 2 小时。如果没有 perf 和火焰图,我可能还在猜是数据库慢还是网络慢。

好了,热点函数定位就讲到这里。记住一句话:不要猜,要测。perf 和火焰图就是你的“性能显微镜”。

核心总结:

  • perf 基于采样,频率 99Hz 是黄金值
  • 火焰图宽度代表 CPU 占用,重点关注“平顶”区域
  • 三种常见模式:平顶山、尖塔群、深井
  • 优化前后都要采样,对比验证效果
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 21:21:26

昇腾NPU变长序列训练实战:从dynamic shape到variable_seq_lengths

1. 为什么“变长序列训练”在昇腾上不是加个 flag 就能跑通的事你是不是也遇到过这样的场景:模型结构写好了,数据 pipeline 也按 PyTorch 惯例做了 padding mask 处理,本地 CPU/GPU 上训得稳稳当当;一迁到昇腾 NPU 上&#xff0c…

作者头像 李华
网站建设 2026/9/28 21:21:02

MOS管为什么会炸?

MOS管为什么会炸? 从波形看懂几种常见失效原因 空载能启动,一加负载就炸;室温调试没问题,装进机箱运行一阵却烧了;PWM 明明留了死区,上下管仍然一起损坏。碰到这些现象,换一颗电流更大、耐压更…

作者头像 李华
网站建设 2026/9/28 21:20:23

Python第四周学习笔记

文章目录前言一、元组(tuple)1.元组特点2. 常用操作示例二、函数1. 什么是函数2. 分类三、变量作用域四、数据类型转换五、文件操作1. 打开模式2. 基础读写六、递归(简单理解)总结前言 在掌握了变量、分支 if、while 循环、break…

作者头像 李华