TorchInductor GPU profiling

本节列出了有用的命令和工作流程,帮助你深入分析模型在 TorchInductor 中的性能。当模型运行速度未达预期时,你可以逐一检查各个内核。通常,那些占用大部分 GPU 时间的内核最值得关注。之后,你还可能希望直接运行单个内核并检查其性能。PyTorch 提供了涵盖上述所有方面的工具。

相关环境变量

你可以使用以下环境变量来进行分析:
  • TORCHINDUCTOR_UNIQUE_KERNEL_NAMES

    • 默认情况下,TorchInductor 将 Triton 内核命名为 'triton_'。当启用环境变量时,inductor 会在跟踪中生成更具描述性的内核名称,例如 triton_poi_fused_cat_155,其中包含内核类别(poi 表示逐点操作)和原始 ATen 操作符。默认情况下禁用此配置以提高编译缓存命中的机会。

  • TORCHINDUCTOR_BENCHMARK_KERNEL

    • 启用此选项将使感应器代码生成工具能够对单个 Triton 内核进行性能测试。

  • TORCHINDUCTOR_MAX_AUTOTUNE

    • 电感自动调谐器将对更多triton.Configs进行基准测试,并选择性能最优的一个。这样虽然会增加编译时间,但有望提升整体性能。

GPU时间分解

以下是一些将模型的执行时间分解为各个内核步骤的说明。我们将以mixnet_l作为示例。

  1. 运行模型的基准测试脚本:

    TORCHINDUCTOR_UNIQUE_KERNEL_NAMES=1TORCHINDUCTOR_BENCHMARK_KERNEL=1
    python-ubenchmarks/dynamo/timm_models.py–backendinductor–amp
    –performance–dashboard–onlymixnet_l–disable-cudagraphs–training
    

    注意

    该工具根据内核名称确定其类别。启用TORCHINDUCTOR_UNIQUE_KERNEL_NAMES非常重要。

  2. 在输出日志中查找以下内容:
    **Compiledmodulepath:
    /tmp/torchinductor_shunting/qz/cqz7hvhood7y3psp7fy6msjxsxyli7qiwiybizdwtjw6ffyq5wwd.py**
    

对于每个编译的模块,日志中都会有一行记录。如果没有额外的图中断,我们会看到两条记录:一条是正向图的,另一条是反向图的。

对于我们示例命令,分别得到了前向和反向图的编译模块如下:

  1. 现在我们可以详细分析每个编译模块的性能。为了说明目的,我们选择一个前向图模块进行演示。为方便起见,我将该模块命名为fwd.py。直接使用-p参数运行它:

    **>pythonfwd.py-p**
    

查看此示例代码片段中的完整输出日志。

在输出中,你可以看到以下内容:

  • 我们会为配置文件创建一个 Chrome 跟踪文件,这样就可以加载并查看该跟踪文件了。请在日志中查找类似以下内容的行来获取跟踪文件的路径。

Chrome的跟踪文件将会被写入到/tmp/compiled_module_profile.json

将追踪数据加载到 Chrome 中(在 Chrome 浏览器中访问 chrome://tracing 并按 UI 提示加载文件),会显示出如下界面:

{BASE_RAW_UPLOAD_URL}/pytorch-doc-2.5/c7ad2fb12543c9a37678cd1fbe590bae.png

你可以通过缩放来查看配置文件。

  • 我们通过类似的日志行来报告 GPU 使用时间占总时间的百分比:

    GPU占用率:102.88%

    有时你可能会看到一个大于100%的值。这是因为PyTorch在启用性能分析时使用内核执行时间,而在禁用性能分析时使用墙钟时间。启用性能分析可能会稍微影响内核执行时间的准确性。但总体来说,这不应该是一个大问题。

    如果我们将模型设置为densenet121并使用小批量处理,会发现GPU的繁忙时间占比非常低。

    (Forward graph) Percent of time when GPU is busy: 32.69%
    

    这意味着模型的CPU开销很高。这一结论与启用cudagraphs能显著提高densenet121性能的事实相符。

  • 我们可以将 GPU 时间分为不同类型内核的类别。在 mixnet_l 示例中,我们可以看到

    • 逐点内核占28.58%

    • 缩减内核占比为13.85%

    • 持久化缩减内核占 3.89%

    • 其余的是用于mm/conv的cutlass/cudnn内核,占比为56.57%

    您可以在每个内核类别报告的最后一行(即摘要行)中找到此信息。

  • 我们还会对某些类别的内核进行深入探讨。例如,让我们来看看缩减内核:

    {BASE_RAW_UPLOAD_URL}/pytorch-doc-2.5/18e9b1faa3bdf0c23d21aabb8bafc838.png

    我们可以看到每个独立缩减内核的执行时间的有序表格,并且可以看到每个内核被调用的次数。这些信息有几个方面非常有帮助:

    • 如果一个内核仅占用0.1%的运行时间,即使对其进行优化,也最多只能获得0.1%的整体提升。因此,不值得在这上面花费过多精力。

    • 如果一个内核占用了2%的运行时间,将其性能提高一倍只能带来1%的整体收益,但这证明了努力是值得的。

单独基准测试Triton内核

假设我们想更仔细地查看 triton_red_fused\__native_batch_norm_legit_functional_16,这是最耗时的缩减内核,占正向图总执行时间的2.19%。

我们可以在fwd.py中查找内核名称,并发现类似的注释:

# 内核路径: /tmp/torchinductor_shunting/jk/cjk2vm3446xrk7rth7hr6pun7xxo3dnzubwcn6ydrpifal4eykrz.py

{BASE_RAW_UPLOAD_URL}/pytorch-doc-2.5/86301e35ba59784164ad56b14fd8b3c7.png

为了方便,我将它重命名为 k.py。这里是在GitHub Gist上的文件链接。

k.py 是一个独立的 Python 模块,包含了内核代码和其基准测试。

直接运行 k.py 会显示其执行时间及带宽:

{BASE_RAW_UPLOAD_URL}/pytorch-doc-2.5/b2b53c24b6abd7c6cd7a35a3f4c96c6d.png

我们可以运行以下命令来检查 max-autotune 是否对此内核有所帮助:

**TORCHINDUCTOR_MAX_AUTOTUNE=1python/tmp/k.py**

我们还可以临时添加更多的缩减启发式算法,然后重新运行脚本,以检查这如何有助于改进内核。

本页目录