使用perf生成Flame Graph(火焰图)

本文介绍了如何使用perf生成Flame Graph,一种用于可视化性能分析的工具。通过编写简单的脚本,可以方便地进行性能采样并生成火焰图。在没有kernel debuginfo包的情况下,perf依然能提供便利,但信息可能不那么详细。脚本包括使用perf record进行采样,然后利用perl脚本进行数据处理和图形生成。读者可以根据脚本中的Usage说明,指定采样时间来针对特定进程或系统整体进行性能分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  使用SystemTap脚本制作火焰图,内存较少时,分配存储采样的数组可能失败,需要编写脚本,还要安装kernel的debuginfo包。使用perf的话,相对来说要简单一些。不过在有kernel的debuginfo包的时候,采样显示的信息要更丰富一些。
  为了使用perf制作火焰图方便,我编写了下面的脚本,贴上来备忘,也方便需要的人。
  脚本如下:
if [ $ # -ne 1 ];then
echo "Usage: $0 seconds"
exit
<think>我们正在讨论如何解析perf生成火焰以理解性能数据。根据用户提供的引用和之前关于火焰的讨论,我们可以总结出以下关键点: 1. **火焰生成流程**(引用[2][4]): - 使用`perf record`采集性能数据(指定采样频率、进程ID、调用栈信息等) - 生成`perf.data`二进制文件 - 使用FlameGraph工具链将数据转换为SVG格式的火焰 2. **火焰结构解析**(引用[1][3]): - **X轴**:表示样本数量(即时间占比),不显示时间单位 - **Y轴**:表示调用栈深度,顶层是正在执行的函数,下层是其调用者 - **每个矩形**:代表一个函数调用栈中的函数 - 宽度:该函数占用的CPU时间比例 - 颜色:随机生成(无特殊含义)或按库着色(如用户代码/内核代码) 3. **关键分析原则**(引用[1]): - 关注最宽的顶层函数(消耗CPU最多的函数) - 寻找"平顶山"(表示该函数自身消耗大量CPU) - 注意"陡峭塔尖"(表示深层调用链) 4. **混合A*典型分析场景**(结合先前回答): - 状态扩展函数(`expandState`)宽度过大 → 算法核心逻辑瓶颈 - 碰撞检测(`isStateValid`)出现高塔 → 检测函数调用层次过深 - 代价查询(`getCost`)频繁出现尖峰 → 高频小函数调用开销 现在,让我们具体说明如何解析火焰: ### 一、火焰结构解析(以混合A*为例) ```plaintext 示例火焰调用栈(自上而下阅读): 100% ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 65% ██████████████ HybridAStar::plan() ├─ 48% ▓▓▓▓▓▓▓▓▓▓ HybridAStar::expandState() │ ├─ 20% ▒▒▒▒▒ CollisionChecker::isStateValid() │ └─ 15% ░░░░ ReedsShepp::calcPath() └─ 10% ▒▒▒▒▒ reconstructPath() 15% ▓▓▓▓▓▓▓▓ Costmap2D::getCost() ... ``` ### 二、关键分析步骤 1. **定位最宽顶层块**(直接消耗CPU的函数) - 示例:中`HybridAStar::plan()`占65%宽度 → 主要耗时在规划流程 - 技巧:点击火焰可动态放大,悬浮显示函数名和占比[^3] 2. **分析热路径**(从底向上追踪调用链) ```mermaid graph TD A[最顶层函数] --> B[直接调用者] B --> C[次级调用者] C --> D[...] ``` - 示例路径:`plan() → expandState() → isStateValid() → getCost()` - 该路径总耗时:65% × 48% × 20% ≈ 6.24% 总CPU时间 3. **区分自耗时与子调用**(关键优化点) - 函数矩形分为两部分: - 下半部:函数自身代码耗时(纯函数体) - 上半部:调用其他函数的开销(子调用) - 示例:若`expandState()`矩形中: - 下半部占30% → 状态扩展自身计算耗时 - 上半部占18% → 调用碰撞检测等子函数耗时 ### 三、典型瓶颈模式识别 | 模式 | 示 | 优化方向 | |--------------|---------------|------------------------------| | **胖矩形** | [#######] | 算法逻辑优化/并行化 | | **高塔** | 窄而高的堆叠 | 减少调用层次/内联函数 | | **密集尖峰** | 高频细柱 | 缓存优化/降低调用频率 | | **平台** | 顶部平坦矩形 | 热点函数针对性优化 | ### 四、量化分析技巧 1. **精确占比计算**: ```bash perf report -n --stdio # 输出示例: # Samples: 20K of event 'cpu-clock' # 45.2% 4500 hybrid_astar [.] CollisionChecker::isStateValid ``` - 实际耗时 = (样本数/总样本数) × 采集时间 2. **多维度对比**: - 优化前后火焰宽度对比(相同时间尺度) - 不同输入场景的火焰差异(如空旷vs复杂环境) > 💡 **黄金法则**:优先优化宽度>5%的函数,高频尖峰(>1000次/秒)考虑重构,>8层调用链需简化[^1][^3]。 ### 五、混合A*专项分析案例 1. **碰撞检测优化前**: ```plaintext isStateValid [40%] ├─ getCost [30%] # 高频访问代价地 ├─ footprintCheck [8%] └─ coordinateTransform [2%] ``` 2. **优化后(分级检测)**: ```plaintext isStateValid [15%] ├─ fastBoundingBoxCheck [5%] # 新增快速检查 └─ preciseCollisionCheck [10%] # 降低调用频率 ``` 通过火焰可清晰看到: - `getCost`宽度从30%降至5% - 新增的`fastBoundingBoxCheck`仅占5% --- §§相关问题§§ 1. 如何用perf report命令深入分析火焰中的特定函数? 2. 火焰中出现`[unknown]`符号该如何解决? 3. 混合A*算法中如何验证碰撞检测优化的实际效果? 4. perf采样频率设置多少最为合理? [^1]: 火焰通过可视化调用栈深度和函数宽度直接暴露CPU热点,特别适合分析计算密集型算法如混合A*。 [^2]: 分级碰撞检测策略通过快速淘汰无效状态显著减少计算量,是路径规划中的通用优化范式。 [^3]: 代价地的局部缓存能有效利用CPU缓存局部性原理,尤其适用于SLAM等高频访问场景。 [^4]: GPU并行化需结合Nsight工具分析核函数效率,避免显存带宽成为新瓶颈。</think>### 如何解析perf生成火焰进行性能分析 #### 一、火焰基础结构解析 1. **坐标轴含义**: - **X轴**:表示样本数量(时间占比),不显示具体时间单位 - **Y轴**:表示调用栈深度,顶层是正在执行的函数 - **矩形宽度**:函数在采样中出现的频率(即CPU耗时占比)[^1][^3] 2. **关键视觉特征**: ```mermaid graph LR A[火焰] --> B[宽矩形] A --> C[高塔形] A --> D[尖峰] B --> E[核心耗时函数] C --> F[深层调用链] D --> G[高频小函数] ``` #### 二、四步分析法 1. **定位最宽顶层函数** - 火焰顶部最宽的矩形是首要优化目标 - 示例:若`HybridAStar::expandState()`占60%宽度 → 消耗60% CPU时间[^1] ```bash perf report -g --stdio | grep expandState # 输出示例:60.12% hybrid_astar [.] HybridAStar::expandState ``` 2. **追踪热路径(Hot Path)** - 从宽矩形向下追踪调用链: ```plaintext plan() [35%] └─ expandState() [60%] └─ isStateValid() [40%] └─ getCost() [30%] # 高频尖峰 ``` - 优化建议:优先优化宽度>5%的函数链[^3] 3. **识别特殊模式** - **平顶山**:函数自身耗时高(如复杂算法) - **陡峭高塔**:深层嵌套调用(需简化逻辑) - **分散尖峰**:高频小函数(考虑合并或缓存) 4. **量化分析** ```python # 计算函数真实耗时 总采样数 = perf_report.total_samples 函数采样数 = perf_report.function_samples 实际耗时 = (函数采样数 / 总采样数) * 采集时间 ``` #### 三、混合A*典型瓶颈模式 | 模式 | 火焰形状 | 典型函数 | 优化方向 | |------|------------|----------|----------| | 状态扩展瓶颈 | 宽矩形 | `expandState()` | 算法优化/并行化 | | 碰撞检测高塔 | 细高堆叠 | `isStateValid()->checkCollision()` | 分级检测 | | 代价查询尖峰 | 高频窄条 | `Costmap2D::getCost()` | 局部缓存 | | 内存操作 | 分散尖峰 | `malloc()/memcpy()` | 内存池 | #### 四、操作实例分析 1. **生成火焰**(引用[2][4]) ```bash # 采集数据(30秒,99Hz采样) perf record -F 99 -p $(pidof hybrid_astar) -g -- sleep 30 # 生成SVG火焰 perf script | ./stackcollapse-perf.pl | ./flamegraph.pl > astar_flame.svg ``` 2. **分析示例**: ```plaintext hybrid_astar_node (100%) ├── plan() [35%] │ └── expandState() [60%] ★ 宽矩形 │ ├── heuristic() [10%] │ └── isStateValid() [40%] ★ │ ├── getCost() [30%] ★★ 尖峰 │ └── polygonCheck() [10%] └── publishPath() [5%] └── malloc() [3%] ◆ 系统开销 ``` - 优化级:`getCost()` > `isStateValid()` > `expandState()` #### 五、高级技巧 1. **区分CPU类型**: - 用户空间函数:常规矩形 - 内核函数:红色边框(如`[kernel]`前缀) - 库函数:绿色填充(如`libstdc++.so`) 2. **多维度对比**: ```mermaid barChart title 优化前后对比 x-axis 函数 y-axis 耗时占比% series 优化前:[60, 40, 30] series 优化后:[35, 15, 8] labels [expandState, isStateValid, getCost] ``` 3. **隐藏瓶颈识别**: - 查找`[unknown]`:需添加调试符号(编译时加`-g`) - 短时高频函数:放大火焰观察微秒级调用 > 🔍 **关键原则**:宽度>5%的函数优先优化,高度>8层的调用链需简化,尖峰>1000次/秒的函数需重构[^1][^3] ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值