火焰图颜色发灰、宽度失真、点击无详情等问题,根源在于self值在采集、传输、映射、归一化、渲染五环节中被错误处理;需校验数据源字段、动态计算色阶、统一符号清洗、用trace总耗时归一化、分批渲染。
火焰图颜色不随耗时变化?检查 self 和 total 指标绑定
火焰图颜色发灰、看不出热点,大概率是前端把采样值映射错了。慢查询分析面板通常用 self(当前函数独占时间)做色阶依据,但有些后端返回的是 total(含子调用),直接塞给渲染库会导致色阶拉平。
- 确认数据源字段:查接口响应里每个 frame 是否含
self字段;若只有duration或inclusive,需在服务端或前端转换 - 前端渲染前加校验:
if (!frame.self) frame.self = frame.total - sum(child.self),避免空值污染色阶计算 - 色阶范围别硬编码:用实际数据的
Math.max(...frames.map(f => f.self))动态算上限,否则新上线高耗时 SQL 会全挤在最深色一档
横向宽度不准,函数栈被截断?注意采样精度与归一化方式
火焰图宽度代表时间占比,但常见问题是“看着宽的函数点开却没多少子调用”,本质是归一化用了错误分母。
- 必须用整个 trace 的总耗时(而非单个 query 的
execution_time)做归一化基准,否则并发查询混在一起时宽度失真 - 避免在数据库层做采样聚合:PostgreSQL 的
pg_stat_statements默认只存平均值,要开track_activity_query_size+ 自定义采样器才能拿到原始调用栈 - 前端缩放时别重绘整个 SVG:对宽度过万节点的火焰图,用
transform: scaleX()替代重计算每个<rect></rect>宽度,性能差 5 倍以上
点击函数无详情弹窗?检查 flame graph 与 profile 数据的 symbol 映射
点不动、弹窗空白,90% 是符号未对齐。火焰图节点名(如 exec_simple_query)和实际 profile 数据里的符号(如 exec_simple_query@postgres)不一致,导致查不到上下文。
- 后端输出前统一清理符号:用正则
symbol.replace(/@.*/, '')剥离编译器/版本后缀,前后端保持同一清洗逻辑 - 避免依赖调试符号:生产环境通常没
.debug段,用addr2line -e /usr/lib/postgresql/*/bin/postgres预生成符号表更可靠 - 前端缓存映射关系:对重复出现的
exec_simple_query,只首次请求后端补全源码行号,后续直接读本地 Map
Chrome DevTools 里火焰图卡死?禁用非必要帧渲染
加载 10MB+ 的火焰图 JSON 时,浏览器内存暴涨甚至崩溃,不是数据大,而是默认渲染策略太激进。
- 关掉 hover tooltip 的实时计算:把
onMouseEnter里原本的getStackInfo(frame)改成节流 + 缓存,首次悬停才解析 - 折叠深度 > 15 的栈:用
if (frame.depth > 15) return { name: '…', children: [] }提前截断,人眼根本分不清第 16 层和第 17 层的区别 - 用
requestIdleCallback分批渲染:每帧只处理 200 个节点,比setTimeout更准,避免阻塞主线程
真正难的不是配颜色或调宽度,是让每一帧的 self 值在采集、传输、映射、归一化、渲染这五个环节里都不被悄悄改写——漏掉任意一环,火焰图就从诊断工具变成装饰画。











