Skip to content

Profiling 正文

页面目标

这页把“怎么测”和“测出来之后怎么判断”分开讲,避免 profiling 只停留在采集数据。

适用人群

  • 想先把性能问题定位清楚,再决定改代码的人。
  • 正在看训练、推理或分布式 benchmark,但还不知道瓶颈在哪的人。
  • 想把 profiling 结果和 benchmark、回归验证连起来的人。

不适用人群

  • 只想找一个现成优化技巧,不关心问题归因的人。
  • 还没有基本训练/推理流程概念的人。
  • 只看单次结果,不打算做对照和验证的人。

你应该如何开始读

  • 先读 17 -> 20 -> 13,把“测什么、怎么测、怎么看”立住。
  • 如果你关心训练,接着看 2.5 -> 19 -> 32
  • 如果你关心多卡和通信,再接 2.8 -> 33 -> 34 -> 42
  • 最后回到 2.9,把 profiling 结论放进验证闭环。

故事线

一个最典型的 profiling 故事,是“任务没报错,但就是越来越慢”。最开始大家往往会盯着某个算子,觉得是实现问题;但把链路一拉开,往往会发现慢点分散在三个地方:训练步里有重算,显存峰值压住了 batch,多卡同步还在等通信。

第一步先跑 17 -> 20 -> 13,把时间热点和等待热点拆出来。 第二步再跑 2.5 -> 19 -> 32,确认是不是 activation 和 checkpointing 在拖慢训练。 第三步再跑 2.8 -> 33 -> 34 -> 42,确认并行收益是不是被通信吃掉。 最后把结果放回 2.9,比较优化前后是否真的更稳、更快。

这个故事的重点不是“图很多”,而是先定位,再归因,最后验证。

具体案例

案例 1:训练变慢,但看不出是哪一步慢

现象是:整体 step time 慢了,但单看训练日志看不出异常。
判断链路是:先看 17 -> 20 -> 13,把时间热点、单步热点和等待热点拆开;再看 2.5 -> 19 -> 32,确认是不是重算和 checkpointing 把训练拖慢。

常见结论是:

  • 如果时间热点集中在少数 step,往往是局部算子或局部输入造成的。
  • 如果重算比例升高,checkpointing 可能是在省显存,但在赔时间。

这个案例的重点是:先把“慢”拆成可解释的层,再决定是不是值得改。

案例 2:多卡 benchmark 不稳定

现象是:同一组多卡实验,结果波动大,有时看起来快,有时看起来不快。
判断链路是:先看 2.8 -> 33 -> 34 -> 42,把通信热点、同步等待和 benchmark 结果对上;再看 33 -> 34 -> 2.9,确认是不是验证口径不一致。

常见结论是:

  • 如果同步等待占比高,波动通常会被放大。
  • 如果 benchmark 口径不统一,优化前后对比就没有意义。

这个案例的重点是:profiling 不只是看热点,还要看实验设计是否足够稳。

案例 3:推理看起来慢,但根因不是 decode

现象是:大家第一反应是生成策略不够快,实际一查发现首 token 延迟更高。
判断链路是:先看 2.6 -> 20 -> 21 -> 22,把 attention 和 cache 先拆开;再看 22 -> 36 -> 41,确认是不是 cache 命中率和请求组织出了问题。

常见结论是:

  • decode 慢不一定是采样慢,很多时候是 prefill 和缓存链路拖住了。
  • 先把 request / cache / schedule 分开,再谈生成策略。

这个案例的重点是:profiling 的价值在于把“以为慢在 A”变成“实际上慢在 B”。

采集层

先把数据采对,再谈归因。采集层的目标不是“尽量多”,而是“足够解释问题”。

采集对象你要回答什么典型入口
时间慢在哪一步、哪一层17 -> 20
显存哪类对象在占空间18 -> 19
通信同步和等待是否拖慢系统42 -> 34
端到端优化前后是否真的变化33 -> 34 -> 2.9

归因层

采集完之后,不要马上改代码,先把问题归到能解释的层级上。

问题类型先看什么需要确认什么
compute17 -> 20 -> 13是算子慢、层慢,还是流程慢
memory2.5 -> 19 -> 32是 activation、重算,还是峰值误判
communication2.8 -> 33 -> 34 -> 42是同步等待、气泡,还是 overlap 没生效

验证层

归因之后,必须回到实验验证。profiling 的价值最后要落到“能不能被重复证明”。

  • before / after 是否有稳定差异。
  • 看优化是否改变了 latencythroughputpeak memory
  • 看 benchmark 是否和线上请求分布一致。
  • 看问题是否在后续回归里再次出现。

一页速记

层级你主要关心什么在本专题里怎么看
采集层先把时间、显存和热点抓出来先看 17 -> 20 -> 13
归因层慢到底慢在 compute、memory 还是 communication再看 2.5 -> 19 -> 322.8 -> 33 -> 34 -> 42
验证层改动后是不是确实变快了最后回到 2.9 和 benchmark
方法层不是看图本身,而是定位到能动手的粒度先测、再解释、最后验证

建议阅读顺序

  1. 先看 17 -> 20 -> 13,把时间、显存和瓶颈定位立住。
  2. 再看 2.5 -> 19 -> 32,观察训练侧显存和重算问题。
  3. 再看 2.8 -> 33 -> 34 -> 42,看分布式和通信瓶颈。
  4. 最后回到 2.9,把 profiling 结论收进项目验证闭环。

典型案例

系统慢了,但不知道慢在哪

最典型的 profiling 问题是“感觉慢,但说不清慢在哪里”。先看 17 -> 20 -> 13,把时间、显存和热点分出来;如果是训练场景,再看 2.5 -> 19 -> 32;如果是分布式场景,再看 2.8 -> 33 -> 34 -> 42

结果看起来变好了,但不确定是不是真优化

有时候某次实验跑得更快了,但这不一定代表优化成立。要回到 33 -> 34 -> 2.9,确认是不是 benchmark 口径、请求分布或波动造成的假改善。

显存降了,但吞吐也掉了

这类问题不能只看峰值显存,要看 2.5 -> 19 -> 322.6 -> 22 -> 35 后,是否把 latency / throughput 也一起带坏了。profiling 的目标是把代价显式化,而不是把问题藏起来。

典型阅读链

  • 如果你想先抓时间热点,先读 17 -> 20 -> 13
  • 如果你想先看显存和重算,先读 2.5 -> 19 -> 32
  • 如果你想先看通信和并行问题,先读 2.8 -> 33 -> 34 -> 42
  • 如果你想先确认优化是否成立,先读 33 -> 34 -> 2.9

对照表

场景先看什么重点差异
训练慢2.5 -> 19 -> 32看 activation、重算和训练步耗时
推理慢17 -> 20 -> 13看 attention、cache 和单步热点
多卡慢2.8 -> 33 -> 34 -> 42看同步等待、通信和气泡
结果不稳2.9看单次波动、对照和验证口径

简单规则

  • 先确认问题类型:compute、memory 还是 communication。
  • 再看单步、单层还是全流程。
  • 再决定要不要动代码。

常见错误

  • 只采集数据,不做归因。
  • 只看单次结果,不看波动和对照。
  • 把 profiling 当成纯“找快慢”工具。
  • 看到热点就改代码,没有先确认是不是系统级瓶颈。

FAQ

  • ProfilingBenchmark 有什么区别?前者更偏诊断和归因,后者更偏结果验证;两者通常要一起用。
  • 这个专题是不是只管性能?不是,它也管显存、通信和调度的观测,只是最终都要回到性能判断。
  • 为什么要先看 0E?因为它先把调试、显存和性能判断的基础观测习惯立起来。
  • 如果只能做一次 profiling,优先看什么?优先看能解释主要瓶颈的指标,比如时间、显存或通信等待,而不是把所有日志都采一遍。

深入阅读

  • 想看完整排障故事,去 Profiling 深入阅读
  • 想快速回顾摘要、清单和案例,继续留在本页即可。

相关专题

检查清单

  • 先确认问题是 computememory 还是 communication
  • 再看瓶颈是集中在单步、单层,还是整个流程。
  • 再看优化目标是降时延、提吞吐,还是省显存。
  • 再回到 2.5 / 2.6 / 2.8 / 2.9,确认 profiling 结论能不能落到具体动作。
  • 最后把方法和结果写成可复用的检查项,而不是一次性结论。

小结

Profiling 的核心不是“多看几张图”,而是“把问题定位到可以动手的粒度”。

Released under the MIT License.