前言
在分析性能问题时,我们常常会使用查日志、jmap或jstack等工具。然而,jstack的默认输出形式通常不够直观,需要人工分析,这对开发者来说显然不够高效。本文将探讨一种更直观的工具——Flame Graph(火焰图)。
什么是Flame Graph
Flame Graph是一种用于软件执行情况可视化的工具,广泛应用于性能 profiling 和 debugging领域。它通过图形化的方式展示程序执行的深度和频率,帮助开发者快速定位性能瓶颈。
Flame Graph的工作原理
Flame Graph的核心功能并非直接生成图形,而是对性能数据进行采集和分析。根据不同的 profile 类型,采集工具也会有所不同:
- CPU profile:采集进程的stack trace,常用Linux的perf命令。
- Memory profile:采集malloc等系统调用,用于分析内存使用情况。
- Off-CPU profile:分析被阻塞的线程,通常用于线程调度问题。
例如,使用perf命令对进程进行CPU profile采集,命令格式如下:
sudo perf record -F 99 -p 1234 -g --sleep 60
生成的stack trace数据需要通过perf工具进行处理,最后提交给Flame Graph进行展示。Flame Graph的图形化输出显示了调用频率和深度,y轴表示调用深度,x轴表示频率。
Flame Graph的优势在于其直观性,但其局限性在于每个小格子显示信息有限,需要点击查看详细方法名。
附:Profile的页面快速执行构建工具
为了方便开发者快速获取profile结果,一些系统代码整合了profile功能到页面端。以下是一个常见的实现示例:
package org.apache.hadoop.hdds.server; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; … public class ProfileServlet extends HttpServlet { … protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { … // 如果 Pied 未指定,使用当前进程 final int duration = getInteger(req, "duration", DEFAULT_DURATION_SECONDS); final Output output = getOutput(req); final Event event = getEvent(req); … // 发起 profiling 命令 List cmd = new ArrayList<>(); cmd.add(asyncProfilerHome + PROFILER_SCRIPT); cmd.add("-e"); cmd.add(event.getInternalName()); cmd.add("-d"); cmd.add(duration + ""); … process = runCmdAsync(cmd); … } … }
该工具支持多种 profile 类型和参数,例如事件类型(如cpu、alloc等)、时间间隔、输出格式等。通过指定不同的参数,可以灵活配置 profiling行为。
引用
[1]. Apache Hive documentation
[2]. Async Profiler GitHub repository