FinCodeCow · Обзор AI-инфраструктуры

Компилятор PyTorch, OpenAI Triton и бэкенды XLA

Обзор главы 14 книги Chris Fregly «AI Systems Performance Engineering» (O'Reilly, 2026) — от TorchDynamo и AOT Autograd до TorchInductor, Triton и PyTorch/XLA
Об источнике

Настоящий материал представляет собой обзор главы 14 книги Chris Fregly, «AI Systems Performance Engineering: Optimizing Model Training and Inference Workloads with GPUs, CUDA, and PyTorch», O'Reilly Media, 2026 (Copyright © 2026 Flux Capacitor, LLC).

Прямые цитаты из книги выделены отдельными блоками с пометкой «Цитата из книги». Остальной текст — систематизированное изложение содержания главы, сопоставление с актуальными данными, проверка прогнозов и дополнительные замечания, выходящие за пределы текста главы. Цитаты приводятся в ограниченном объёме в целях обзора и критического анализа.

§Контекст главы

Глава 14 книги Fregly посвящена динамическому стеку компиляции PyTorch — от захвата графа на уровне байт-кода Python до генерации высокопроизводительных GPU-ядер через OpenAI Triton и альтернативный бэкенд XLA для TPU и других ускорителей. Материал охватывает как внутреннее устройство TorchDynamo, AOT Autograd, PrimTorch IR и TorchInductor, так и практические аспекты написания кастомных ядер, отладки компилятора и масштабирования на распределённые конфигурации.

Цитата из книги · Глава 14

«Компилятор PyTorch прошёл путь от экспериментальной возможности до production-ready стека, который обеспечивает производительность, близкую к рукописным библиотекам, при сохранении гибкости eager-режима разработки. Конвейер TorchDynamo → AOT Autograd → PrimTorch IR → TorchInductor → Triton/LLVM представляет собой вертикально интегрированный компилятор, где каждый этап решает свою задачу: захват графа, объединение проходов, канонизация, генерация кода и компиляция в PTX».

Изложение содержания

В главе подчёркивается, что производительность современных AI-моделей всё чаще определяется не только качеством отдельных ядер, но и качеством компиляции. Автоматическое слияние операций, подбор тайлов, генерация Tensor Core-кода — всё это берёт на себя компилятор. Задача инженера — понять, как работает этот стек, чтобы использовать его возможности и диагностировать проблемы.

• • •

IСтек компиляции PyTorch

Конвейер torch.compile состоит из четырёх последовательных этапов, каждый из которых решает свою задачу:

  1. TorchDynamo — захват графа вычислений на уровне байт-кода Python.
  2. AOT Autograd — совместная трассировка прямого и обратного проходов.
  3. PrimTorch IR — канонизация операций к ограниченному набору примитивов.
  4. TorchInductor — генерация оптимизированного кода для целевого оборудования.

Далее код транслируется через Triton или LLVM в финальный PTX для NVIDIA GPU, либо через XLA для TPU и других ускорителей.

Рисунок 1. Стек компилятора PyTorch

Пять уровней вертикально интегрированного конвейера

torch.compile() TorchDynamo AOT Autograd PrimTorch IR TorchInductor / XLA
Каждый уровень решает свою задачу: захват, объединение проходов, канонизация, генерация кода
Итоги раздела I
Ключевое положение главы

Компилятор PyTorch — вертикально интегрированный стек, где каждый уровень решает свою задачу. Понимание этой архитектуры необходимо для эффективной диагностики проблем производительности.

Практическое следствие

Производительность модели зависит не только от качества отдельных ядер, но и от качества компиляции. torch.compile автоматизирует большинство оптимизаций.

• • •

IITorchDynamo: захват байт-кода

Цитата из книги · Глава 14

«TorchDynamo (или просто Dynamo) — первый этап компиляции. Он подключается к CPython через Frame Evaluation API, определённый в PEP 523. Этот механизм позволяет Dynamo перехватывать выполнение кадра Python до того, как интерпретатор начнёт его обрабатывать».

Изложение содержания

В главе TorchDynamo описывается как механизм захвата графа на уровне байт-кода. Когда интерпретатор Python выполняет тензорную операцию, Dynamo перехватывает её и добавляет как узел в граф FX, откладывая реальное выполнение. Этот процесс продолжается до тех пор, пока не встретится код, который Dynamo не может обработать. В этот момент происходит разрыв графа (graph break), и неподдерживаемые операции выполняются в обычном eager-режиме.

Для простой функции:

def f(x, y):
    z = x.sin() + y
    return z.sum()

TorchDynamo создаст FX Graph, примерно эквивалентный следующему псевдокоду:

graph():
    %x : Tensor = Placeholder[target=x]
    %y : Tensor = Placeholder[target=y]
    %sin : Tensor = torch.sin(%x)
    %add : Tensor = torch.add(%sin, %y)
    %sum : Tensor = torch.sum(%add)
    return %sum

Каждый узел соответствует вызову примитивного оператора ATen, такого как aten::sin, aten::add, aten::sum.

Guard'ы и перекомпиляция

TorchDynamo расставляет guard'ы — проверки на значения Python, которые влияют на трассировку графа: формы тензоров, типы данных, значения глобальных переменных. Эти guard'ы гарантируют, что если что-то изменится, скомпилированный граф будет признан недействительным и при необходимости перекомпилирован.

Устранение разрывов графа

Разрывы графа — главный враг производительности. Каждый разрыв означает, что оптимизированный граф обрезан, и вводится больше накладных расходов Python. Распространённые причины разрывов и способы их устранения:

  • Побочные эффекты: оператор print() не может быть захвачен в граф. Решение — обернуть его в проверку if not torch._dynamo.is_compiling().
  • Поток управления, зависящий от данных: конструкция if tensor.sum() > 0: вызывает разрыв графа. Решения: torch.where(), torch.cond() или рефакторинг.
  • In-place операции: мутации вроде x.add_(y) могут вызывать разрывы графа. Решение — переписать в out-of-place форме.
  • Динамические списки Python: добавление тензоров в список Python внутри функции запутывает Dynamo. Решение — использовать torch.stack() вместо динамического построения списков.
Итоги раздела II
Ключевое положение главы

TorchDynamo захватывает граф на уровне байт-кода через Frame Evaluation API. Разрывы графа — главный враг производительности.

Практическое следствие

Устраняйте разрывы: заменяйте print() на проверку is_compiling(), используйте torch.where() вместо if, переписывайте in-place операции.

• • •

IIIAOT Autograd: слияние прямого и обратного проходов

Цитата из книги · Глава 14

«AOT Autograd работает иначе. Он пропускает захваченный граф прямого прохода через движок autograd в функциональном режиме, записывая операции обратного прохода заранее. Результат — статический граф обратного прохода, объединённый с графом прямого прохода».

Изложение содержания

В главе AOT Autograd описывается как этап, на котором создаётся совместный граф прямого и обратного проходов. Это позволяет компилятору оптимизировать всю последовательность вычислений как единое целое, а не как набор отдельных операций.

AOT Autograd предоставляет несколько ключевых возможностей:

  • Слияние ядер через границу проходов: компилятор может объединить поэлементную операцию в прямом проходе с соответствующей операцией градиента в обратном проходе в одно ядро.
  • Повторное использование буферов: компилятор может повторно использовать промежуточные результаты между прямым и обратным проходами, когда это безопасно.
  • Общее исключение подвыражений: поскольку весь граф известен заранее, компилятор может найти и устранить повторяющиеся вычисления.
Итоги раздела III
Ключевое положение главы

AOT Autograd создаёт совместный граф прямого и обратного проходов, что позволяет оптимизировать всю последовательность вычислений как единое целое.

Практическое следствие

Слияние ядер через границу проходов и повторное использование буферов снижают пиковое потребление памяти и ускоряют обучение.

• • •

IVPrimTorch IR: упрощение набора операторов

Цитата из книги · Глава 14

«PyTorch имеет более 2000 операций в своём полном API. Для компилятора это огромная проблема — каждый бэкенд должен уметь обрабатывать все эти операции. PrimTorch IR решает эту задачу, сокращая разнообразие операций до примерно 250 примитивных».

Изложение содержания

В главе PrimTorch IR описывается как этап канонизации операций. Многие сложные операции PyTorch разлагаются на примитивы. Например, in-place операция x.add_(y) преобразуется в функциональный add с последующим явным копированием.

Стабильный интерфейс PrimTorch IR означает, что для поддержки нового ускорителя разработчикам нужно реализовать только 250 примитивов, а не тысячи операций ATen. Это радикально снижает порог входа для новых аппаратных платформ.

Итоги раздела IV
Ключевое положение главы

PrimTorch IR сокращает более 2000 операций PyTorch до ~250 примитивов, что упрощает поддержку новых аппаратных платформ.

Практическое следствие

In-place операции преобразуются в функциональные плюс отдельные узлы копирования, что упрощает оптимизацию и планирование памяти.

• • •

VTorchInductor: генерация кода

Цитата из книги · Глава 14

«TorchInductor (или просто Inductor) — стандартный бэкенд компилятора PyTorch. Он принимает оптимизированный FX Graph, состоящий из операций aten + PrimTorch IR, и генерирует высокопроизводительный код для NVIDIA GPU, AMD GPU, CPU и других платформ».

Изложение содержания

В главе TorchInductor описывается как бэкенд, который превращает граф в высокопроизводительный код. Для NVIDIA GPU он использует JIT-компилятор OpenAI Triton для генерации GPU-ядер. Triton понижается до NVIDIA PTX через LLVM NVPTX, не вызывая NVCC для компиляции ядер.

Автотюнинг

TorchInductor включает автотюнер, построенный на возможностях Triton. При первой компиляции кода с режимом max-autotune Inductor тратит дополнительное время на бенчмаркинг различных вариантов ядер — разные размеры блоков, тайлов, количества варпов. Самый быстрый вариант кэшируется и используется в дальнейшем.

CUDA Graphs

TorchInductor использует CUDA Graphs для захвата последовательностей ядер во время выполнения. Это уменьшает накладные расходы на запуск при каждой итерации, что особенно полезно для инференса. Режимы reduce-overhead и max-autotune активируют CUDA Graphs.

Совет

Для стабильных форм и latency-критичного инференса предпочитайте torch.compile(mode="max-autotune") после того, как количество рекомпиляций под контролем. Держите границу захвата узкой (per-layer или attention block), чтобы уменьшить инвалидацию графа из-за ragged batching.

Итоги раздела V
Ключевое положение главы

TorchInductor — стандартный бэкенд компилятора PyTorch. Для NVIDIA GPU он использует Triton, который понижается до PTX через LLVM NVPTX.

Практическое следствие

Автотюнинг и CUDA Graphs дают значительный выигрыш для больших и критичных нагрузок. Для небольших моделей выгода может быть незначительной.

• • •

VIOpenAI Triton: кастомные ядра на Python

Цитата из книги · Глава 14

«Triton использует модель SPMD (Single-Program, Multiple-Data), в отличие от SIMT-модели CUDA. Ядра Triton работают на уровне блоков потоков (CTA), а не отдельных потоков. Вам не нужно явно управлять потоками или варпами — компилятор Triton делает это за вас».

Изложение содержания

В главе Triton описывается как Python-ориентированный DSL для написания GPU-ядер. Он снижает барьер входа для разработчиков, не знакомых с CUDA C++. Под капотом Triton компилируется в PTX через LLVM.

Простое ядро сложения векторов:

import triton
import triton.language as tl

BLOCK_SIZE = 1024

@triton.jit
def vector_add_kernel(x_ptr, y_ptr, out_ptr, n_elements,
                      BLOCK_SIZE: tl.constexpr):
    pid = tl.program_id(axis=0)
    block_start = pid * BLOCK_SIZE
    offsets = block_start + tl.arange(0, BLOCK_SIZE)
    mask = offsets < n_elements
    x = tl.load(x_ptr + offsets, mask=mask)
    y = tl.load(y_ptr + offsets, mask=mask)
    result = x + y
    tl.store(out_ptr + offsets, result, mask=mask)

Здесь BLOCK_SIZE — константа времени компиляции. tl.arange(0, BLOCK_SIZE) возвращает вектор индексов, а tl.load и tl.store выполняют векторизованные загрузки и сохранения с маскированием на границах.

Регистрация кастомных ядер в PyTorch

Чтобы ядро Triton было видимым для torch.compile и не вызывало разрыв графа, зарегистрируйте его как кастомную операцию:

from torch.library import triton_op, wrap_triton

@triton_op("my_triton_lib::vector_add", mutates_args=())
def vector_add(x: Tensor, y: Tensor) -> Tensor:
    output = torch.empty_like(x)
    n_elements = x.numel()
    grid = lambda meta: (triton.cdiv(n_elements, meta['BLOCK_SIZE']),)
    wrap_triton(vector_add_kernel)[grid](
        x, y, output, n_elements, BLOCK_SIZE=1024
    )
    return output

c = torch.ops.my_triton_lib.vector_add(a, b)

Автотюнинг

Производительность GPU-ядра высокочувствительна к параметрам времени компиляции. Встроенный автотюнер Triton автоматизирует поиск оптимальных настроек:

@triton.autotune(
    configs=[
        triton.Config({'BLOCK_M': 64, 'BLOCK_N': 64, 'BLOCK_K': 64},
                      num_warps=4, num_stages=2),
        triton.Config({'BLOCK_M': 128, 'BLOCK_N': 128, 'BLOCK_K': 64},
                      num_warps=8, num_stages=2),
        triton.Config({'BLOCK_M': 128, 'BLOCK_N': 128, 'BLOCK_K': 128},
                      num_warps=8, num_stages=3,
                      num_consumer_groups=2,
                      num_buffers_warp_spec=3),
    ],
    key=['M', 'N', 'K'],
)
@triton.jit
def gemm_kernel(...):
    ...

Во время первого вызова Triton JIT-компилирует и тестирует каждую конфигурацию. Самая быстрая кэшируется для данного ключа, производного от характеристик входа.

Итоги раздела VI
Ключевое положение главы

Triton использует модель SPMD, абстрагируя управление потоками и варпами. Ядра пишутся на Python и компилируются в PTX через LLVM.

Практическое следствие

Регистрация кастомных ядер через torch.library.triton_op() делает их видимыми для torch.compile. Автотюнинг автоматизирует поиск оптимальных конфигураций.

• • •

VIIPyTorch XLA: бэкенд для TPU и не-CUDA ускорителей

Цитата из книги · Глава 14

«PyTorch XLA — отдельный бэкенд компиляции, ориентированный на Google Cloud TPU и другие ускорители, не поддерживаемые TorchInductor. XLA отображает операции PyTorch в IR графа XLA и выполняет их с использованием среды выполнения целевого оборудования».

Изложение содержания

В главе PyTorch XLA описывается как альтернативный бэкенд для не-CUDA ускорителей. Активация: torch.compile(..., backend="openxla"). XLA используется для Google Cloud TPU, внутреннего инференс-чипа Meta (MTIA), а также кастомных чипов AWS Inferentia и Trainium через AWS Neuron SDK.

PyTorch/XLA работает на модели ленивого выполнения (lazy execution): операции записываются в граф и выполняются только когда результат строго нужен. Это принципиально отличается от модели TorchDynamo, которая перехватывает байт-код.

Новый мост Dynamo для XLA (бета на 2025 год) использует guard-систему Dynamo для более надёжного захвата графов, чем ленивая трассировка.

Особенности и ограничения

  • Статические формы: XLA оптимизирован для статических форм. Новые формы вызывают полную перекомпиляцию, что дорого для latency-чувствительного инференса.
  • Время компиляции: Компиляция на TPU может занимать минуты, что делает итеративный цикл «правка-запуск-правка» намного медленнее, чем на CUDA.
  • Scan operator: В PyTorch/XLA 2.6 появился экспериментальный scan-оператор, ускоряющий компиляцию для повторяющихся блоков кода.
  • Host offloading: В PyTorch/XLA 2.6 также появилась возможность временно перемещать тензоры с TPU в память хоста CPU для размещения больших моделей на меньшем количестве TPU.
Итоги раздела VII
Ключевое положение главы

PyTorch XLA — альтернативный бэкенд для TPU и не-CUDA ускорителей. Активируется через backend="openxla".

Практическое следствие

XLA оптимизирован для статических форм. Новые формы вызывают полную перекомпиляцию. Для TPU время компиляции может быть значительным.

• • •

VIIIРаспределённое обучение и компилятор

Цитата из книги · Глава 14

«PyTorch DDP работает с TorchDynamo, явно разрывая графы в точках синхронизации all-reduce. Это ожидаемое поведение: компилятор компилирует редукцию каждого бакета градиента отдельно, чтобы коммуникация одного бакета перекрывалась с вычислением обратного прохода следующего».

Изложение содержания

В главе подчёркивается, что разрывы графа на границах коммуникации DDP необходимы для сохранения перекрытия вычислений и коммуникации. TorchDynamo + DDP работает с производительностью, аналогичной eager-режиму DDP, и может даже превосходить его в масштабе.

PyTorch FSDP поддерживается в скомпилированном режиме с use_original_params=True. Лучшая практика — оборачивать каждый подмодуль (например, каждый блок трансформера) в отдельный подмодуль FSDP. Dynamo создаёт явные разрывы на границах подмодулей FSDP, позволяя коммуникации каждого шарда перекрываться с вычислениями.

Итоги раздела VIII
Ключевое положение главы

Разрывы графа на границах коммуникации DDP и FSDP необходимы для сохранения перекрытия вычислений и коммуникации.

Практическое следствие

Оборачивайте подмодули в FSDP индивидуально для пошардовой компиляции и экономии памяти. Тестируйте FSDP с torch.compile сначала на меньшей конфигурации.

• • •

IXПроверка прогнозов и актуальные данные

Книга Fregly писалась в 2025 году. С тех пор появились новые данные, которые позволяют проверить некоторые из утверждений главы и уточнить цифры.

Подтверждено Прогноз 1: компилятор PyTorch станет production-ready

«Компилятор PyTorch прошёл путь от экспериментальной возможности до production-ready стека».

Подтверждено. TorchInductor и Triton широко используются в production. PyTorch 2.x с torch.compile стал стандартом для оптимизации производительности. NVIDIA продолжает обновлять Triton для поддержки новейших архитектур, включая Blackwell.

Подтверждено Прогноз 2: Triton займёт значительную долю в генерации GPU-кода

«На момент написания TorchInductor всё ещё использует Triton в качестве основного пути генерации GPU-кода».

Подтверждено. Triton остаётся основным путём генерации GPU-кода в TorchInductor. Однако появились конкуренты: NVIDIA анонсировала Python-ориентированные библиотеки CUDA (cuTile, CuTe DSL), а также появились альтернативные подходы, такие как Cypress и LLM-агенты, транслирующие ядра напрямую в PTX.

Подтверждено Прогноз 3: PyTorch/XLA будет развиваться, но останется нишевым решением

«PyTorch/XLA — отдельный бэкенд компиляции, ориентированный на Google Cloud TPU и другие ускорители, не поддерживаемые TorchInductor».

Подтверждено. PyTorch/XLA продолжает развиваться (версия 2.6 в 2025 году), но остаётся нишевым решением для TPU и не-CUDA ускорителей. Google Cloud продолжает поддерживать и улучшать его, но для NVIDIA GPU стандартом является TorchInductor + Triton.

Частично подтверждено Прогноз 4: FlexAttention достигнет производительности FlashAttention

«FlexAttention fused kernels достигают до 85–90% производительности современного FlashAttention».

Частично подтверждено. FlexAttention действительно достиг значительного прогресса. С новым Flash-бэкендом на GB200 он может достигать 1.6–3.2x ускорения над Triton-реализацией для прямого прохода. Однако для некоторых паттернов и конфигураций FlashAttention всё ещё остаётся быстрее.

Подтверждено Прогноз 5: автоматизация оптимизаций будет расти

«Современные компиляторные фреймворки автоматически выполняют часть оптимизаций».

Подтверждено. TorchInductor автоматически выполняет слияние операций, автотюнинг и использует CUDA Graphs. PyTorch/XLA 2.6 представил scan-оператор и host offloading. Тренд на автоматизацию продолжается.

• • •

XДополнительные замечания, выходящие за пределы главы

Глава описывает компилятор PyTorch, но оставляет за скобками несколько аспектов, которые проявились в реальной практике.

Ограничения динамических форм

Дополнительные замечания

Глава описывает поддержку динамических форм, но не рассматривает ограничения. CUDA Graphs требуют статических форм. При включении dynamic=True CUDA Graphs не используются. Для переменных длин последовательностей рекомендуется mode="default" или mode="max-autotune-no-cudagraphs". Это важный компромисс между гибкостью и производительностью.

Сложность отладки компилятора

Дополнительные замечания

Глава описывает инструменты отладки, но не подчёркивает сложность диагностики проблем компилятора. Graph breaks, рекомпиляции, проблемы с числовой корректностью — всё это требует глубокого понимания внутреннего устройства компилятора. Инструменты вроде TORCH_LOGS и torch._dynamo.explain() помогают, но кривая обучения остаётся высокой.

Взаимодействие с TensorRT и другими бэкендами

Дополнительные замечания

Глава фокусируется на TorchInductor и XLA, но не рассматривает взаимодействие с TensorRT. В production-средах TensorRT часто используется для инференса, и torch.compile может интегрироваться с ним. Это важный аспект для production-развёртываний, который остаётся за пределами главы.

Экосистема Triton

Дополнительные замечания

Глава описывает Triton, но не упоминает экосистему вокруг него. Triton активно развивается, появляются новые возможности: TLX (Triton Language Extensions) для низкоуровневого контроля, поддержка Blackwell с инструкциями tcgen05, MXFP4/MXFP8. Сообщество GPU MODE активно способствует развитию Triton.

• • •

XIДополнительные выводы

  1. Компилятор PyTorch — центральный элемент производительности. Понимание его архитектуры необходимо для эффективной оптимизации. TorchDynamo, AOT Autograd, PrimTorch IR и TorchInductor образуют вертикально интегрированный стек.
  2. Triton снижает барьер входа для написания GPU-ядер. Python-ориентированный DSL и автотюнинг делают высокопроизводительные ядра доступными для более широкого круга разработчиков.
  3. Разрывы графа — главный враг производительности. Устранение разрывов через torch.where(), torch.cond() и рефакторинг — ключевая задача инженера.
  4. CUDA Graphs и статические формы — компромисс. Для latency-критичного инференса со стабильными формами max-autotune даёт максимальную производительность. Для переменных форм требуется default или max-autotune-no-cudagraphs.
  5. XLA — нишевое решение для TPU. Для NVIDIA GPU стандартом остаётся TorchInductor + Triton.
  6. Автоматизация оптимизаций продолжает расти. TorchInductor автоматически выполняет слияние, автотюнинг и использует CUDA Graphs. PyTorch/XLA 2.6 представил scan-оператор и host offloading.
Общий итог обзора

Глава 14 книги Fregly — систематический разбор стека компиляции PyTorch. Ключевая идея: компилятор PyTorch прошёл путь от эксперимента до production-ready стека, который обеспечивает производительность, близкую к рукописным библиотекам. Для инженера это означает, что понимание внутреннего устройства компилятора — от TorchDynamo до TorchInductor — необходимо для эффективной оптимизации и диагностики проблем. По мере движения к моделям в сотни триллионов параметров и системам вроде NVL72 роль компилятора будет только расти.

Источники: Chris Fregly, «AI Systems Performance Engineering» (O'Reilly, 2026), Глава 14 — цитаты приводятся в ограниченном объёме в целях обзора и критического анализа. Документация PyTorch, TorchInductor, Triton, PyTorch/XLA; MLPerf Training/Inference v5.0; открытые публикации NVIDIA и Google Cloud.

FinCodeCow · AI Infrastructure Review

PyTorch Compiler, OpenAI Triton, and XLA Backends

A review of Chapter 14 of Chris Fregly's «AI Systems Performance Engineering» (O'Reilly, 2026) — from TorchDynamo and AOT Autograd to TorchInductor, Triton, and PyTorch/XLA
About the source

This material is a review of Chapter 14 of Chris Fregly, «AI Systems Performance Engineering: Optimizing Model Training and Inference Workloads with GPUs, CUDA, and PyTorch», O'Reilly Media, 2026 (Copyright © 2026 Flux Capacitor, LLC).

Direct quotes from the book are marked with separate blocks labeled «Quote from the book». The rest of the text is a systematized exposition of the chapter's content, a comparison with current data, forecast verification, and additional observations that go beyond the chapter's text. Quotes are provided in limited volume for review and critical analysis purposes.

§Chapter Context

Chapter 14 of Fregly's book is dedicated to the dynamic PyTorch compilation stack — from graph capture at the Python bytecode level to the generation of high-performance GPU kernels via OpenAI Triton and the alternative XLA backend for TPUs and other accelerators. The material covers the internals of TorchDynamo, AOT Autograd, PrimTorch IR, and TorchInductor, as well as practical aspects of writing custom kernels, debugging the compiler, and scaling to distributed configurations.

Quote from the book · Chapter 14

«The PyTorch compiler has come a long way from an experimental feature to a production-ready stack that delivers performance close to hand-written libraries while retaining the flexibility of eager development. The pipeline TorchDynamo → AOT Autograd → PrimTorch IR → TorchInductor → Triton/LLVM is a vertically integrated compiler where each stage solves its own task: graph capture, pass merging, canonicalization, code generation and compilation to PTX».

Exposition of content

The chapter emphasizes that the performance of modern AI models is increasingly determined not only by the quality of individual kernels but also by the quality of compilation. Automatic operation fusion, tile selection, Tensor Core code generation — all of this is handled by the compiler. The engineer's task is to understand how this stack works in order to leverage its capabilities and diagnose problems.

• • •

IPyTorch Compiler Stack

The torch.compile pipeline consists of four sequential stages, each solving its own task:

  1. TorchDynamo — graph capture at the Python bytecode level.
  2. AOT Autograd — joint tracing of forward and backward passes.
  3. PrimTorch IR — canonicalization of operations to a limited set of primitives.
  4. TorchInductor — generation of optimized code for the target hardware.

The code is then translated through Triton or LLVM into final PTX for NVIDIA GPUs, or through XLA for TPUs and other accelerators.

Figure 1. The PyTorch Compiler Stack

Five levels of a vertically integrated pipeline

torch.compile() TorchDynamo AOT Autograd PrimTorch IR TorchInductor / XLA
Each layer solves its own task: capture, pass merging, canonicalization, code generation
Section I Summary
Key point of the chapter

The PyTorch compiler is a vertically integrated stack where each level solves its own task. Understanding this architecture is necessary for effective performance diagnostics.

Practical consequence

Model performance depends not only on the quality of individual kernels but also on the quality of compilation. torch.compile automates most optimizations.

• • •

IITorchDynamo: Bytecode Capture

Quote from the book · Chapter 14

«TorchDynamo (or simply Dynamo) is the first stage of compilation. It hooks into CPython through the Frame Evaluation API defined in PEP 523. This mechanism lets Dynamo intercept execution of a Python frame before the interpreter begins processing it».

Exposition of content

In the chapter, TorchDynamo is described as a bytecode-level graph capture mechanism. When the Python interpreter executes a tensor operation, Dynamo intercepts it and adds it as a node in an FX graph, deferring its actual execution. This continues until it encounters code that Dynamo cannot handle. At that point, a graph break occurs, and unsupported operations run in normal eager mode.

For a simple function:

def f(x, y):
    z = x.sin() + y
    return z.sum()

TorchDynamo creates an FX Graph roughly equivalent to the following pseudocode:

graph():
    %x : Tensor = Placeholder[target=x]
    %y : Tensor = Placeholder[target=y]
    %sin : Tensor = torch.sin(%x)
    %add : Tensor = torch.add(%sin, %y)
    %sum : Tensor = torch.sum(%add)
    return %sum

Each node corresponds to a call to a primitive ATen operator such as aten::sin, aten::add, aten::sum.

Guards and recompilation

TorchDynamo installs guards — checks on Python values that affect graph tracing: tensor shapes, dtypes, global variable values. These guards ensure that if something changes, the compiled graph is invalidated and recompiled if needed.

Eliminating graph breaks

Graph breaks are the main enemy of performance. Every break means the optimized graph is truncated and more Python overhead is introduced. Common causes of breaks and how to fix them:

  • Side effects: print() cannot be captured in the graph. Fix: wrap in a check if not torch._dynamo.is_compiling().
  • Data-dependent control flow: if tensor.sum() > 0: causes a graph break. Fixes: torch.where(), torch.cond(), or refactoring.
  • In-place operations: mutations like x.add_(y) may cause breaks. Fix: rewrite out-of-place.
  • Dynamic Python lists: appending tensors to a Python list confuses Dynamo. Fix: use torch.stack() instead.
Section II Summary
Key point of the chapter

TorchDynamo captures graphs at the bytecode level via the Frame Evaluation API. Graph breaks are the main enemy of performance.

Practical consequence

Eliminate breaks: replace print() with is_compiling() checks, use torch.where() instead of if, rewrite in-place operations.

• • •

IIIAOT Autograd: Merging Forward and Backward Passes

Quote from the book · Chapter 14

«AOT Autograd works differently. It passes the captured forward graph through the autograd engine in functional mode, recording backward operations ahead of time. The result is a static backward graph merged with the forward graph».

Exposition of content

In the chapter, AOT Autograd is described as the stage where a joint forward and backward graph is created. This allows the compiler to optimize the entire computation sequence as a single whole rather than as a collection of individual operations.

AOT Autograd provides several key capabilities:

  • Cross-pass kernel fusion: the compiler can fuse an element-wise operation in the forward pass with its corresponding gradient operation in the backward pass into a single kernel.
  • Buffer reuse: the compiler can reuse intermediate results between forward and backward passes when safe.
  • Common subexpression elimination: since the whole graph is known ahead of time, the compiler can find and eliminate repeated computations.
Section III Summary
Key point of the chapter

AOT Autograd creates a joint forward and backward graph, allowing the entire computation sequence to be optimized as a single whole.

Practical consequence

Cross-pass kernel fusion and buffer reuse reduce peak memory consumption and accelerate training.

• • •

IVPrimTorch IR: Simplifying the Operator Set

Quote from the book · Chapter 14

«PyTorch has over 2000 operations in its full API. For a compiler, that is a huge problem — every backend must be able to handle all of them. PrimTorch IR solves this by reducing the diversity of operations to around 250 primitives».

Exposition of content

In the chapter, PrimTorch IR is described as the operation canonicalization stage. Many complex PyTorch operations are decomposed into primitives. For example, the in-place operation x.add_(y) is transformed into a functional add followed by an explicit copy.

A stable PrimTorch IR interface means that to support a new accelerator, developers only need to implement 250 primitives instead of thousands of ATen operations. This radically lowers the barrier to entry for new hardware platforms.

Section IV Summary
Key point of the chapter

PrimTorch IR reduces over 2000 PyTorch operations to ~250 primitives, simplifying support for new hardware platforms.

Practical consequence

In-place operations are converted to functional plus separate copy nodes, simplifying optimization and memory planning.

• • •

VTorchInductor: Code Generation

Quote from the book · Chapter 14

«TorchInductor (or simply Inductor) is the default backend of the PyTorch compiler. It takes the optimized FX Graph consisting of aten + PrimTorch IR operations and generates high-performance code for NVIDIA GPUs, AMD GPUs, CPUs and other platforms».

Exposition of content

In the chapter, TorchInductor is described as the backend that turns the graph into high-performance code. For NVIDIA GPUs, it uses the OpenAI Triton JIT compiler to generate GPU kernels. Triton lowers to NVIDIA PTX via LLVM NVPTX without invoking NVCC to compile the kernels.

Autotuning

TorchInductor includes an autotuner built on Triton's capabilities. On the first compile with the max-autotune mode, Inductor spends extra time benchmarking different kernel variants — different block sizes, tiles, warp counts. The fastest variant is cached and used subsequently.

CUDA Graphs

TorchInductor uses CUDA Graphs to capture sequences of kernels at runtime. This reduces per-iteration launch overhead, which is especially useful for inference. The modes reduce-overhead and max-autotune enable CUDA Graphs.

Tip

For stable shapes and latency-critical inference, prefer torch.compile(mode="max-autotune") once recompilations are under control. Keep the capture boundary narrow (per-layer or attention block) to reduce graph invalidation from ragged batching.

Section V Summary
Key point of the chapter

TorchInductor is the default PyTorch compiler backend. For NVIDIA GPUs it uses Triton, which lowers to PTX via LLVM NVPTX.

Practical consequence

Autotuning and CUDA Graphs provide significant gains for large, critical workloads. For small models, the benefit may be negligible.

• • •

VIOpenAI Triton: Custom Kernels in Python

Quote from the book · Chapter 14

«Triton uses the SPMD (Single-Program, Multiple-Data) model, unlike CUDA's SIMT model. Triton kernels operate at the level of thread blocks (CTAs), not individual threads. You don't have to explicitly manage threads or warps — the Triton compiler does it for you».

Exposition of content

In the chapter, Triton is described as a Python-oriented DSL for writing GPU kernels. It lowers the barrier to entry for developers unfamiliar with CUDA C++. Under the hood, Triton compiles to PTX via LLVM.

A simple vector addition kernel:

import triton
import triton.language as tl

BLOCK_SIZE = 1024

@triton.jit
def vector_add_kernel(x_ptr, y_ptr, out_ptr, n_elements,
                      BLOCK_SIZE: tl.constexpr):
    pid = tl.program_id(axis=0)
    block_start = pid * BLOCK_SIZE
    offsets = block_start + tl.arange(0, BLOCK_SIZE)
    mask = offsets < n_elements
    x = tl.load(x_ptr + offsets, mask=mask)
    y = tl.load(y_ptr + offsets, mask=mask)
    result = x + y
    tl.store(out_ptr + offsets, result, mask=mask)

Here BLOCK_SIZE is a compile-time constant. tl.arange(0, BLOCK_SIZE) returns a vector of indices, and tl.load and tl.store perform vectorized loads and stores with boundary masking.

Registering custom kernels in PyTorch

To make a Triton kernel visible to torch.compile and avoid graph breaks, register it as a custom operation:

from torch.library import triton_op, wrap_triton

@triton_op("my_triton_lib::vector_add", mutates_args=())
def vector_add(x: Tensor, y: Tensor) -> Tensor:
    output = torch.empty_like(x)
    n_elements = x.numel()
    grid = lambda meta: (triton.cdiv(n_elements, meta['BLOCK_SIZE']),)
    wrap_triton(vector_add_kernel)[grid](
        x, y, output, n_elements, BLOCK_SIZE=1024
    )
    return output

c = torch.ops.my_triton_lib.vector_add(a, b)

Autotuning

GPU kernel performance is highly sensitive to compile-time parameters. Triton's built-in autotuner automates the search for optimal settings:

@triton.autotune(
    configs=[
        triton.Config({'BLOCK_M': 64, 'BLOCK_N': 64, 'BLOCK_K': 64},
                      num_warps=4, num_stages=2),
        triton.Config({'BLOCK_M': 128, 'BLOCK_N': 128, 'BLOCK_K': 64},
                      num_warps=8, num_stages=2),
        triton.Config({'BLOCK_M': 128, 'BLOCK_N': 128, 'BLOCK_K': 128},
                      num_warps=8, num_stages=3,
                      num_consumer_groups=2,
                      num_buffers_warp_spec=3),
    ],
    key=['M', 'N', 'K'],
)
@triton.jit
def gemm_kernel(...):
    ...

On the first call, Triton JIT-compiles and benchmarks each configuration. The fastest one is cached for a given key derived from input characteristics.

Section VI Summary
Key point of the chapter

Triton uses the SPMD model, abstracting thread and warp management. Kernels are written in Python and compiled to PTX via LLVM.

Practical consequence

Registering custom kernels via torch.library.triton_op() makes them visible to torch.compile. Autotuning automates the search for optimal configurations.

• • •

VIIPyTorch XLA: Backend for TPUs and Non-CUDA Accelerators

Quote from the book · Chapter 14

«PyTorch XLA is a separate compilation backend targeting Google Cloud TPU and other accelerators not supported by TorchInductor. XLA maps PyTorch operations to the XLA graph IR and executes them using the target hardware runtime».

Exposition of content

In the chapter, PyTorch XLA is described as an alternative backend for non-CUDA accelerators. Activation: torch.compile(..., backend="openxla"). XLA is used for Google Cloud TPU, Meta's internal inference chip (MTIA), and custom AWS Inferentia and Trainium chips via the AWS Neuron SDK.

PyTorch/XLA works on the lazy execution model: operations are recorded into a graph and only executed when the result is strictly needed. This is fundamentally different from the TorchDynamo model, which intercepts bytecode.

The new Dynamo bridge for XLA (beta in 2025) uses the Dynamo guard system for more robust graph capture than lazy tracing.

Features and limitations

  • Static shapes: XLA is optimized for static shapes. New shapes cause full recompilation, which is expensive for latency-sensitive inference.
  • Compilation time: TPU compilation can take minutes, making the edit-run-edit iteration cycle much slower than on CUDA.
  • Scan operator: PyTorch/XLA 2.6 introduced an experimental scan operator that speeds up compilation for repeated code blocks.
  • Host offloading: PyTorch/XLA 2.6 also introduced the ability to temporarily move tensors from TPU to host CPU memory to fit large models on fewer TPUs.
Section VII Summary
Key point of the chapter

PyTorch XLA is an alternative backend for TPUs and non-CUDA accelerators. Activated via backend="openxla".

Practical consequence

XLA is optimized for static shapes. New shapes cause full recompilation. For TPUs, compilation time can be significant.

• • •

VIIIDistributed Training and the Compiler

Quote from the book · Chapter 14

«PyTorch DDP works with TorchDynamo, explicitly breaking graphs at all-reduce synchronization points. This is expected behavior: the compiler compiles the reduction for each gradient bucket separately so that communication of one bucket overlaps with the backward computation of the next».

Exposition of content

In the chapter, it is emphasized that graph breaks at DDP communication boundaries are necessary to preserve compute-communication overlap. TorchDynamo + DDP works with performance similar to eager DDP and can even surpass it at scale.

PyTorch FSDP is supported in compiled mode with use_original_params=True. Best practice is to wrap each submodule (e.g., each transformer block) in a separate FSDP submodule. Dynamo creates explicit breaks at FSDP submodule boundaries, allowing communication of each shard to overlap with compute.

Section VIII Summary
Key point of the chapter

Graph breaks at DDP and FSDP communication boundaries are necessary to preserve compute-communication overlap.

Practical consequence

Wrap submodules in FSDP individually for per-shard compilation and memory savings. Test FSDP with torch.compile on a smaller configuration first.

• • •

IXForecast Verification and Current Data

Fregly's book was written in 2025. Since then, new data has emerged that allows verification of some of the chapter's claims and clarification of figures.

Confirmed Forecast 1: PyTorch compiler will become production-ready

«The PyTorch compiler has come a long way from an experimental feature to a production-ready stack».

Confirmed. TorchInductor and Triton are widely used in production. PyTorch 2.x with torch.compile has become the standard for performance optimization. NVIDIA continues to update Triton to support the latest architectures, including Blackwell.

Confirmed Forecast 2: Triton will capture a significant share of GPU code generation

«At the time of writing, TorchInductor still uses Triton as its primary GPU code generation path».

Confirmed. Triton remains the primary GPU code generation path in TorchInductor. However, competitors have emerged: NVIDIA announced Python-oriented CUDA libraries (cuTile, CuTe DSL), and alternative approaches such as Cypress and LLM agents translating kernels directly to PTX have appeared.

Confirmed Forecast 3: PyTorch/XLA will evolve but remain a niche solution

«PyTorch/XLA is a separate compilation backend targeting Google Cloud TPU and other accelerators not supported by TorchInductor».

Confirmed. PyTorch/XLA continues to evolve (version 2.6 in 2025) but remains a niche solution for TPUs and non-CUDA accelerators. Google Cloud continues to support and improve it, but for NVIDIA GPUs the standard is TorchInductor + Triton.

Partially confirmed Forecast 4: FlexAttention will reach FlashAttention performance

«FlexAttention fused kernels reach up to 85–90% of modern FlashAttention performance».

Partially confirmed. FlexAttention has indeed made significant progress. With the new Flash backend on GB200, it can achieve 1.6–3.2× speedup over the Triton implementation for the forward pass. However, for some patterns and configurations, FlashAttention remains faster.

Confirmed Forecast 5: Automation of optimizations will grow

«Modern compiler frameworks automatically perform some optimizations».

Confirmed. TorchInductor automatically performs operation fusion, autotuning, and uses CUDA Graphs. PyTorch/XLA 2.6 introduced the scan operator and host offloading. The trend toward automation continues.

• • •

XAdditional Observations Beyond the Chapter

The chapter describes the PyTorch compiler but omits several aspects that have emerged in real-world practice.

Dynamic shape limitations

Additional observations

The chapter describes dynamic shape support but does not cover its limitations. CUDA Graphs require static shapes. When dynamic=True is enabled, CUDA Graphs are not used. For variable-length sequences, mode="default" or mode="max-autotune-no-cudagraphs" is recommended. This is an important trade-off between flexibility and performance.

Complexity of compiler debugging

Additional observations

The chapter describes debugging tools but does not emphasize the complexity of diagnosing compiler issues. Graph breaks, recompilations, numerical correctness issues — all require deep understanding of compiler internals. Tools like TORCH_LOGS and torch._dynamo.explain() help, but the learning curve remains high.

Interaction with TensorRT and other backends

Additional observations

The chapter focuses on TorchInductor and XLA but does not consider interaction with TensorRT. In production environments, TensorRT is often used for inference, and torch.compile can integrate with it. This is an important aspect for production deployments that remains outside the chapter's scope.

Triton ecosystem

Additional observations

The chapter describes Triton but does not mention the ecosystem around it. Triton is actively evolving, with new capabilities emerging: TLX (Triton Language Extensions) for low-level control, Blackwell support with tcgen05 instructions, MXFP4/MXFP8. The GPU MODE community actively contributes to Triton's development.

• • •

XIAdditional Conclusions

  1. The PyTorch compiler is a central element of performance. Understanding its architecture is necessary for effective optimization. TorchDynamo, AOT Autograd, PrimTorch IR, and TorchInductor form a vertically integrated stack.
  2. Triton lowers the barrier to entry for writing GPU kernels. The Python-oriented DSL and autotuning make high-performance kernels accessible to a broader range of developers.
  3. Graph breaks are the main enemy of performance. Eliminating breaks via torch.where(), torch.cond(), and refactoring is a key engineering task.
  4. CUDA Graphs and static shapes are a trade-off. For latency-critical inference with stable shapes, max-autotune delivers maximum performance. For variable shapes, default or max-autotune-no-cudagraphs is required.
  5. XLA is a niche solution for TPUs. For NVIDIA GPUs, the standard remains TorchInductor + Triton.
  6. Automation of optimizations continues to grow. TorchInductor automatically performs fusion, autotuning, and uses CUDA Graphs. PyTorch/XLA 2.6 introduced the scan operator and host offloading.
Overall Review Summary

Chapter 14 of Fregly's book is a systematic review of the PyTorch compilation stack. The key idea: the PyTorch compiler has evolved from an experimental feature to a production-ready stack that delivers performance close to hand-written libraries. For an engineer, this means understanding the compiler's internals — from TorchDynamo to TorchInductor — is necessary for effective optimization and problem diagnosis. As we move toward models with hundreds of trillions of parameters and systems like NVL72, the role of the compiler will only grow.

Sources: Chris Fregly, «AI Systems Performance Engineering» (O'Reilly, 2026), Chapter 14 — quotes provided in limited volume for review and critical analysis purposes. PyTorch, TorchInductor, Triton, PyTorch/XLA documentation; MLPerf Training/Inference v5.0; open publications from NVIDIA and Google Cloud.