← На главную

Python 3.15 получил режим профилирования с почти нулевым оверхедом, но замедляет JIT в 4.5 раза

15.07.2026 09:07 · hackernews

В Python 3.15 появился новый режим профилирования интерпретатора с ультранизкими накладными расходами. Он нужен для записи трейсов выполнения — последовательностей инструкций, которые потом отправляются в JIT-компилятор. JIT в этой версии даёт скромный прирост скорости, и ключ к этому именно новая система профилирования.

Обычно для профилирования интерпретатора используют два подхода. Первый — два отдельных интерпретатора: обычный и профилирующий, между ними переключаются. В тестах на computed goto интерпретаторе это дало замедление примерно на 6% на pyperformance. Вторая схема — режим с булевым флагом, который включает профилирование. Но код распухает, и даже с идеально предсказываемыми ветвлениями процессора это тормозит выполнение.

Разработчики CPython придумали третий вариант — смену таблиц диспетчеризации. Интерпретатор использует таблицу, где каждому опкоду (инструкции) сопоставлен адрес перехода. В CPython 3.15 завели две таблицы: одну для обычной работы, вторую — для профилирования. Переключение — просто присвоение локальной переменной, без ветвлений. Но простая реализация двойной таблицы даёт тот же эффект, что два интерпретатора в одном. Автор нашёл трюк: все инструкции во второй таблице маппятся на один единственный профилирующий обработчик. Он делает всю нужную запись, а потом через первую обычную таблицу перебрасывает на реальную следующую инструкцию. Получается схема fan-in (сводим всё к одной инструкции) / fan-out (раздаём обратно). Вход и выход из режима профилирования — это просто инициализация структур, переключение таблиц макросами ENTER_TRACING и LEAVE_TRACING.

Автор замерил накладные расходы (40 запусков, частота динамических частот отключена). Без профилирования — 1,72 микросекунды. С профилированием и JIT-компиляцией — 7,47 микросекунды. То есть профилирование замедляет интерпретатор всего в 4,5 раза. Для сравнения, системы мета-трассировки вроде PyPy могут давать замедление в 900–1000 раз, хотя там и трассируется гораздо больше кода (сам интерпретатор).

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

Читать оригинал →