Оптимизация производительности
Сначала измеряй, меняй по одному, и доверяй только воспроизводимым числам
- использовать профайлер, чтобы находить реальные горячие точки, а не гадать,
- рассуждать об иерархии памяти и писать дружественные к кэшу раскладки данных,
- устранять лишние копии ссылками, перемещением,
reserveи представлениями, - понимать, что на самом деле делают инлайнинг и оптимизация на этапе компоновки,
- писать честные микробенчмарки, переживающие оптимизатор.
1. Профилируй до оптимизации
Самая дорогая ошибка в работе над производительностью - оптимизировать код, который никогда не был медленным. Программы проводят большую часть времени в малой доле кода, и эта доля, как правило, не там, где ожидает даже опытный инженер. Профайлер измеряет, где действительно тратится время, чтобы вы чинили то, что важно.
Распространены два семейства профайлеров:
- Сэмплирующие профайлеры (perf, VTune, Instruments) прерывают программу много раз в секунду и записывают стек вызовов. Они почти не добавляют накладных расходов и дают статистическую картину горячих точек. Отлично для первого взгляда на реальную нагрузку.
- Инструментирующие профайлеры (callgrind, gprof) вставляют счётный код вокруг каждой функции. Они дают точное число вызовов, но замедляют программу во много раз и искажают крохотные функции.
Оптимизацию ограничивает и арифметика. Закон Амдала гласит: если доля p времени тратится в ускоряемой части и вы сделаете её бесконечно быстрой, вся программа ускорится максимум в 1 / (1 - p) раз. Если в функции 10% времени, её идеализация сэкономит не больше 10% в целом - поэтому профилируйте, чтобы найти большое p, а остальное игнорируйте.