Производительность
Инструменты профилирования (perf, VTune, callgrind), техники оптимизации CPU, идентификация горячего кода и дисциплина бенчмаркинга.
6 вопросов
SeniorПроизводительностьОчень частоКод работает медленно. Как профилировать и оптимизировать?
Код работает медленно. Как профилировать и оптимизировать?
Сначала измерьте perf или VTune и найдите горячий путь. Определите CPU/memory/I/O/lock-bound. Улучшите алгоритм, затем локальность, меньше аллокаций, девиртуализация, SIMD.
Типичные ошибки
- ✗Оптимизировать без профилирования — узкое место редко там, где вы думаете; 90% времени тратится на 10% кода
- ✗Микро-оптимизировать не горячий код — оптимизировать функцию, вызываемую раз в секунду, пропуская функцию, вызываемую 1M раз в секунду
- ✗Бенчмаркировать в debug-режиме —
-O0отключает инлайнинг и SIMD; всегда бенчмаркируйте с-O2или-O3
Уточняющие вопросы
- →Что такое ложное разделение кэш-строк (false sharing) и как обнаружить и исправить это?
- →Как
__builtin_expectпомогает предсказателю переходов CPU?
JuniorТеорияЧастоКогда нужно оптимизировать C++ код, а когда не нужно?
Когда нужно оптимизировать C++ код, а когда не нужно?
Оптимизируйте только после измерений: профилируйте, чтобы найти реальный hot path. Не оптимизируйте до достижения корректности, читаемости и реальных свидетельств узкого места. «Преждевременная оптимизация — корень всех зол» — это про 97% некритичного кода.
Типичные ошибки
- ✗Оптимизировать без профайлера — интуиция плохо угадывает, где реальный hot path
- ✗Игнорировать алгоритмические улучшения (O(n²) → O(n log n)) ради микрооптимизаций не на том цикле
- ✗Путать стоимость читаемости со стоимостью рантайма — нечитаемый код часто платит обслуживанием больше, чем экономит в рантайме
Уточняющие вопросы
- →Какой профайлер вы возьмёте первым на Linux и почему?
- →Что говорит закон Амдала о верхней границе ускорения?
MiddleПроизводительностьЧастоЧто такое cache miss и как его обнаружить/избежать?
Что такое cache miss и как его обнаружить/избежать?
Промах кэша — когда данных нет в L1/L2/L3 и CPU идёт в основную память. Обнаружение через perf или cachegrind; избегать локальностью, prefetch и паддингом против false sharing.
Типичные ошибки
- ✗Оптимизировать кэш без измерений — эффекты кэша зависят от данных; всегда профилируйте реальную рабочую нагрузку
- ✗Применять
alignas(64)к каждой структуре — избыточное выравнивание тратит память и может ухудшить использование кэша; применяйте только к часто разделяемым атомарным данным - ✗Путать ложное разделение с совместным доступом к данным — ложное разделение — это когда два потока пишут в разные переменные, разделяющие кэш-строку; исправление — паддинг/выравнивание, а не блокировка
Уточняющие вопросы
- →В чём разница между кэшем L1/L2/L3 с точки зрения задержки и типичного размера на современных CPU?
- →Как работает аппаратная предвыборка и когда она не срабатывает?
MiddleПроизводительностьЧастоКак иерархия CPU-кеша влияет на выбор структур данных в C++?
Как иерархия CPU-кеша влияет на выбор структур данных в C++?
Кэши: L1 (~4 такта), L2 (~12), L3 (~40), DRAM (~200). Последовательный доступ в 10–100 раз быстрее pointer chasing. vector лучше list, остерегайтесь false sharing.
Типичные ошибки
- ✗Выбирать
std::listради cache locality — pointer chasing наоборот худший случай - ✗Добавлять mutex на каждый элемент против false sharing без измерений
- ✗Класть две горячих атомики в одну cache line — false sharing убивает throughput
Уточняющие вопросы
- →Что такое
std::hardware_destructive_interference_size? - →Когда выбирать SoA вместо AoS?
SeniorПроизводительностьЧастоКаковы подходы к оптимизации кода в C++?
Каковы подходы к оптимизации кода в C++?
Оптимизируйте сверху вниз: лучший алгоритм, затем кэш-дружественные структуры, меньше аллокаций, флаги (-O2/LTO/PGO), девиртуализация, SIMD, параллелизм. Сначала профилируйте.
Типичные ошибки
- ✗Преждевременная оптимизация — трата недель на настройку кода, который не находится на критическом пути; сначала профилируйте, всегда
- ✗Доверять компилятору без проверки сборки — компилятор может не векторизовать цикл, который вы ожидаете; используйте
-fopt-info-vecили godbolt.org для проверки - ✗Забывать, что LTO (оптимизация времени компоновки) может инлайнировать через единицы трансляции — позволяет девиртуализацию и свёртку констант между файлами; всегда включайте для release-сборок
Уточняющие вопросы
- →Что такое PGO (оптимизация на основе профиля) и каковы её затраты на сборку?
- →Как
std::pmr::monotonic_buffer_resourceсравнивается с пользовательским arena allocator?
MiddleПроизводительностьИногдаЧто такое SIMD инструкции? Условия и применение.
Что такое SIMD инструкции? Условия и применение.
SIMD применяет одну инструкцию ко многим элементам (SSE2 128-бит, AVX 256-бит, AVX-512 512-бит). Требует отсутствия зависимостей, выровненный доступ и без ветвлений. Используйте авто-векторизацию или intrinsics.
Типичные ошибки
- ✗Использовать SIMD intrinsics без проверки поддержки набора инструкций целевым CPU — компонуйте с
-mavx2только если все цели деплоя имеют AVX2; иначе используйте диспетчеризацию во время выполнения - ✗Невыровненные загрузки памяти в SIMD коде —
_mm256_loadu_psработает с невыровненными данными, но медленнее; предпочтительно_mm256_load_psс даннымиalignas(32) - ✗Смешивание SIMD и не-SIMD кода в узких циклах — переключение контекста между x87/SSE/AVX может вызывать штрафные циклы; держите горячие пути однородными
Уточняющие вопросы
- →Как написать функцию с диспетчеризацией во время выполнения между путями кода SSE2 и AVX2?
- →Что такое AoS vs SoA структура и как это влияет на эффективность SIMD?