Inlining и LTO

Тема дорожной карты · Modern C++ Developer

Inlining — замена вызова функции её телом прямо в месте вызова. Устраняет call overhead (push регистров, прыжок, возврат) и открывает компилятору возможности дополнительных оптимизаций (constant propagation, dead code elimination, vectorization). LTO (Link-Time Optimization) — расширение inlining-а на границы файлов компиляции: компилятор сохраняет промежуточное представление каждого .cpp в .o, линкер собирает все .o, видит весь код целиком и проводит оптимизации, невозможные при per-file компиляции.

Как это работает

Компилятор принимает решение об inline-инге автоматически на основе размера функции, частоты вызова, оптимизационного уровня (-O2, -O3). Ключевое слово inline — лишь намёк, реальное решение за компилятором. Атрибуты __attribute__((always_inline)) (GCC/Clang) или [[gnu::always_inline]] форсируют, noinline запрещает. Размещение тела функции в .h файле делает её доступной для inline-инга везде, где включён header. LTO включается через -flto на компиляции и линковке. ThinLTO (LLVM) распараллеливает работу — быстрее, но менее агрессивно, чем full LTO. PGO (Profile-Guided Optimization) добавляет к LTO информацию о runtime-частоте веток — лучшие решения inlining и code layout.

Когда применять

Inline по-умолчанию работает хорошо на -O2/-O3 — не нужно вручную помечать каждую функцию inline. Применяйте always_inline для thin wrapper-ов (например, доступ к атомарной переменной, инструкции SIMD-intrinsics). LTO включайте на release-сборках любого нетривиального проекта — typical gain 5-15% в скорости и 2-10% в размере. PGO стоит времени интеграции, если проект performance-critical (game engines, БД, HFT).

Типичные ошибки

Помечание больших функций inline или always_inline — раздувание binary, потеря cache-локальности в icache. Использование inline для определения переменных не из C++17+ — выдаёт duplicate symbol при линковке. Включение LTO без увеличения памяти билд-сервера — линкер OOM-ится на больших проектах. Игнорирование -fno-fat-lto-objects в Debian/Ubuntu — производятся artifacts двойного размера. PGO без полноценного workload-а для profiling — оптимизатор работает на стерильных данных.

Связанные понятия

Полезные ресурсы