
В книге сделан исчерпывающий анализ низкоуровневого устройства процессоров, их архитектур, инструкций, кэша и тонких аспектов оптимизации производительности. На материале тщательно подобранных кейсов, разнообразных бенчмарков и измерений книга демонстрирует потенциально узкие места в работе процессора, устранив которые путем разумных компромиссов можно нарастить его производительность. Рассмотрены инструменты для анализа производительности CPU, средства оптимизации вычислений, доступа к памяти, компоновки памяти, а также детали работы с регистрами и машинным кодом. Особое внимание уделено оптимизации многопоточных приложений.
Книга будет полезна опытным специалистам по разработке программного обеспечения, включая разработчиков приложений, библиотек, компиляторов и операционных систем, а также исследователям и ученым-информатикам.
Почему стоит читать эту книгу?
Современное программное обеспечение очень неэффективно. Процессоры обычно исполняют плохо оптимизированный код, который потребляет больше энергии, чем мог бы, и тем самым способствует выбросам углерода и другим экологическим проблемам. Неэффективное программное обеспечение снижает прибыль компаний и уменьшает их рыночную стоимость. В течение многих лет оптимизация производительности процессоров и чипов считалась узкоспециализированным занятием для «гиков», но сейчас она выходит в мейнстрим, поскольку поставщики программного обеспечения осознают, какое влияние плохо оптимизированный код оказывает на их финансовые показатели. Производительность кода — один из ключевых факторов успеха.
Чему вы научитесь?
Эксперт по производительности вычислительных машин Денис Бахвалов объясняет, как делать низкоуровневые оптимизации с использованием продвинутых методов и инструментов. Прочитав эту книгу, вы сможете находить причины снижения производительности своего приложения и находить разнообразные возможности его оптимизации. Книга изобилует практическими примерами и упражнениями.
Книга посвящена низкоуровневой оптимизации производительности: от анализа архитектуры CPU до работы с регистрами и машинным кодом
Ключевые темы:
- Как правильно измерять производительность кода
- Архитектура современных процессоров
- Обзор техник и инструментов для анализа производительности
- Аппаратные средства для анализа производительности (счетчики и другие механизмы)
- Способы оптимизации доступа к памяти и вычислений
- Устранение промахов в кэше и неправильно предсказанных ветвлений
- Оптимизация раскладки машинного кода
- Векторизация и другие компиляторные оптимизации

Денис Бахвалов начал работу программистом в 2008 году и посвятил большую часть своей карьеры оптимизации взаимодействия между процессором и программным обеспечением. Работая в компании Intel, внедрил множество улучшений производительности в широко используемые промышленные приложения и бенчмарки. Является автором онлайн-курса «Performance Ninja» и ведет свой блог на сайте easyperf.net.
Книгу “Оптимизация производительности современных процессоров. 2-е изд.” можно купить в нашем интенет-магазине.
Предуведомление 9
От автора 11
Целевая аудитория 12
Об авторе 13
Глава 1. Введение 15
1.1. Почему программное обеспечение работает медленно? 16
1.2. Почему нужно уделять внимание производительности? 19
1.3. Что такое анализ производительности? 22
1.4. Что значит оптимизация производительности? 23
1.5. О чем рассказывается в этой книге? 24
1.6. О чем не рассказывается в этой книге? 26
1.7. Упражнения 27
Краткое содержание главы 28
ЧАСТЬ I. АНАЛИЗ ПРОИЗВОДИТЕЛЬНОСТИ
СОВРЕМЕННОГО ПРОЦЕССОРА 29
Глава 2. Анализ производительности 31
2.1. Воздействие помех на современные системы 32
2.2. Измерение производственной производительности 34
2.3. Непрерывное сравнительное тестирование 35
2.4. Ручное тестирование производительности 40
2.5. Программные и аппаратные таймеры 43
2.6. Микробенчмарки 45
2.7. Активное сравнительное тестирование 47
Вопросы и упражнения 48
Краткое содержание главы 48
Глава 3. Микроархитектура центрального процессора 51
3.1. Архитектура набора команд 51
3.2. Конвейерная обработка 52
3.3. Использование параллельного выполнения задач на уровне инструкций (ILP) 56
3.3.1. Внеочередное выполнение 56
3.3.1.1. Статическое планирование 57
3.3.1.2. Динамическое планирование 57
3.3.2. Суперскалярные процессоры 59
3.3.3. Спекулятивное исполнение 59
3.3.4. Прогнозирование ветвления 61
3.4. Мультипроцессоры SIMD 63
3.5. Использование параллельных вычислений на уровне потоков 66
3.5.1. Многоядерные системы 66
3.5.2. Одновременная многопоточная обработка 67
3.5.3. Гибридные конструкции 69
3.6. Иерархия памяти 71
3.6.1. Иерархия кеша 71
3.6.1.1. Размещение данных в кеше 72
3.6.1.2. Поиск данных в кеше 73
3.6.1.3. Управление промахами 73
3.6.1.4. Управление записями 73
3.6.1.5. Другие технологии оптимизации кеша 74
3.6.1.6. Программно-аппаратная предварительная выборка 74
3.6.2. Основная память 75
3.6.2.1. Двойная скорость передачи данных DDR 76
3.6.2.2. GDDR и HBM 79
3.7. Виртуальная память 80
3.7.1. Буфер ассоциативной трансляции (TLB) 82
3.7.2. Большие страницы 83
3.8. Конструкция современных центральных процессоров 84
3.8.1. Фронтенд центрального процессора 84
3.8.2. Бэкенд центрального процессора 87
3.8.3. Блок загрузки и записи 89
3.8.4. Иерархия буфера ассоциативной трансляции 93
3.9. Блок мониторинга производительности 94
3.9.1. Счетчики мониторинга производительности 96
Вопросы и упражнения 97
Краткое содержание главы 98
Глоссарий к рисункам главы 3 99
Глава 4. Терминология и метрики в анализе производительности 103
4.1. Завершенная и выполненная инструкция 104
4.2. Загрузка центрального процессора 104
4.3. CPI и IPC 105
4.4. Микрооперации 107
4.5. Слот конвейера 109
4.6. Такты ядра и относительные такты ядра 110
4.7. Промахи в кеше 111
4.8. Неправильное предсказание ветвления 112
4.9. Метрики производительности 113
4.10. Задержка памяти и пропускная способность 115
4.11. Практический пример. Анализ метрик производительности
для четырех приложений 120
Вопросы и упражнения 126
Краткое содержание главы 127
Глоссарий к рисункам главы 4 127
Глава 5. Методы анализа производительности 129
5.1. Инструментация кода 130
5.2. Трассировка 135
5.3. Сбор событий контроля производительности 136
5.3.1. Мультиплексирование и пересчет событий 138
5.3.2. Использование API-маркеров 140
5.4. Выборочное профилирование 144
5.4.1. Выборка в режиме пользователя и на основе аппаратных событий 145
5.4.2. Поиск горячих точек 146
5.4.3. Сбор стеков вызова 149
5.5. Модель производительности Roofline 151
5.6. Статический анализ производительности 155
5.6.1. Практический пример. Использование UICA для оптимизации
пропускной способности FMA 156
5.7. Отчеты об оптимизации компилятора 161
Вопросы и упражнения 164
Краткое содержание главы 165
Глава 6. Средства процессора для анализа производительности 167
6.1. Нисходящий анализ микроархитектуры 169
6.1.1. TMA на платформах Intel 170
Практический пример. Сокращение числа промахов кеша с помощью TMA 172
6.1.2. TMA на платформах AMD 177
6.1.3. ТМА на платформах Arm 179
6.1.4. Итоги раздела ТМА 183
6.2. Механизмы записи ветвлений 184
6.2.1. LBR на платформе Intel 186
6.2.2. LBR на платформах AMD 189
6.2.3. BRBE на платформах Arm 189
6.2.4. Сбор стека вызовов 189
6.2.5. Выявление горячих ветвей 190
6.2.6. Анализ коэффициента ошибочного предсказания ветвей 191
6.2.7. Точный тайминг машинного кода 192
6.2.8. Оценка вероятности результата ветвления 195
6.2.9. Предоставление обратной связи компилятору 196
6.3. Средства аппаратной выборки 196
6.3.1. PEBS на платформах Intel 196
6.3.2. IBS на платформах AMD 198
6.3.3. SPE на платформе Arm 200
6.3.4. Точные события 201
6.3.5. Анализ обращений к памяти 202
Вопросы и упражнения 203
Краткое содержание главы 203
Глоссарий к рисункам главы 6 204
Глава 7. Обзор инструментов анализа производительности 205
7.1. Профилировщик Intel VTune 205
7.2. AMD uProf 210
7.3. Инструменты Xcode от Apple 213
7.4. Perf для Linux 216
7.5. Диаграмма «пламени» 218
7.6. Трассировка событий в Windows 219
7.7. Специализированные и гибридные профилировщики 221
7.8. Профилирование памяти 228
7.8.1. Использование памяти 228
7.8.2. Практический пример. Анализ выделений памяти в Stockfish 230
7.8.3. Интенсивность использования и объем памяти 233
7.9. Непрерывное профилирование 236
Вопросы и упражнения 240
Краткое содержание главы 240
ЧАСТЬ II. ТЮНИНГ ИСХОДНОГО КОДА 243
Глава 8. Оптимизация доступа к памяти 249
8.1. Структуры данных, дружелюбные для кеша 250
8.1.1. Последовательный доступ к данным 250
8.1.2. Использование подходящих контейнеров 252
8.1.3. Упаковка данных 252
8.1.4. Упорядочивание полей 253
8.1.5. Другие методы реорганизации структуры данных 254
8.2. Динамическое распределение памяти 256
8.3. Устранение ограничений пропускной способности памяти 257
8.4. Уменьшение количества пропусков DTLB 259
8.4.1. Явные большие страницы 260
8.4.2. Прозрачные большие страницы 261
8.4.3. Явные и прозрачные большие страницы 263
8.5. Явная предварительная выборка памяти 264
Вопросы и упражнения 268
Краткое содержание главы 269
Глава 9. Оптимизация вычислений 271
9.1. Зависимость данных 272
9.2. Встраивание функций 278
9.2.1. Оптимизация хвостовых вызовов 280
9.3. Оптимизация циклов 281
9.3.1. Низкоуровневые оптимизации 282
9.3.2. Оптимизация высокого уровня 284
9.3.3. Поиск возможностей оптимизации циклов 287
9.4. Векторизация 288
9.4.1. Автовекторизация компилятора 289
9.4.2. Поиск возможностей векторизации 290
9.4.2.1. Векторизация недопустима 291
9.4.2.2. Векторизация неэффективна 293
9.4.2.3. Векторизованный цикл с использованием скалярной версии 294
9.4.2.4. Неоптимальная векторизация цикла 295
9.4.2.5. Языки с явной векторизацией 296
9.5. Встроенные функции компилятора 297
9.5.1. Библиотеки-обертки для внутренних функций 299
Вопросы и упражнения 301
Краткое содержание главы 302
Глава 10. Оптимизация предсказания ветвлений 303
10.1. Замена ветвлений таблицами поиска 305
10.2. Замена ветвлений арифметическими действиями 306
10.3. Замена ветвлений на условный выбор 306
10.4. Одно ветвление — несколько тестов 309
Вопросы и упражнения 311
Краткое содержание главы 312
Глава 11. Оптимизация компоновки машинного кода 313
11.1. Компоновка машинного кода 314
11.2. Базовый блок 314
11.3. Размещение базовых блоков 315
11.4. Выравнивание базовых блоков 317
11.5. Разделение функций 320
11.6. Упорядочивание функций 321
11.7. Оптимизации, управляемые профилем 323
11.8. Уменьшение промахов ITLB 326
11.9. Практический пример. Измерение размера горячего кода 328
Вопросы и упражнения 332
Краткое содержание главы 332
Глава 12. Дополнительные возможности для оптимизации 333
12.1. Оптимизация под конкретный процессор 333
12.1.1. Расширения ISA 335
12.1.2. Диспетчеризация процессоров 336
12.1.3. Задержки и пропускная способность инструкций 337
12.2. Специфические проблемы микроархитектур 340
12.2.1. Нарушения порядка операций с памятью 340
12.2.2. Невыровненный доступ к памяти 342
12.2.3. Конкуренция двух разных адресов за одну строку кеша 345
12.2.4. Замедленная арифметика со значениями с плавающей запятой 347
12.3. Методы оптимизции низкой задержки 349
12.3.1. Избегайте незначительных ошибок страниц 350
12.3.2. Разогрев кеша 352
12.3.3. Избегайте прерываний TLB 353
12.3.4. Предотвращение непреднамеренного троттлинга ядра 355
12.4. Настройка системы 355
12.5. Практический пример. Чувствительность к размеру кеша последнего уровня 357
Вопросы и упражнения 362
Краткое содержание главы 362
Глоссарий к рисункам главы 12 363
Глава 13. Оптимизация многопоточных приложений 365
13.1. Показатели эффективности работы в параллельном режиме 366
13.2. Масштабирование производительности в многопоточных программах 368
13.2.1. Пример анализа масштабирования при изменении числа потоков 370
Blender 372
Clang 373
Zstandard 375
CloverLeaf 378
CPython 380
Резюме 382
13.3. Планирование задач 383
13.4. Согласованность кеша 386
13.4.1. Протоколы согласования кеша 386
13.4.2. Истинное совместное использование 388
13.4.3. Ложное совместное использование 389
13.5. Инструменты расширенного анализа 391
13.5.1. Coz 391
13.5.2 eBPF и GAPP 392
Вопросы и упражнения 393
Краткое содержание главы 394
Эпилог 395
Благодарности 399
Глоссарий 403
Список основных микроархитектур процессоров 405
Ссылки 407
Приложение A. Уменьшение шумов при измерениях 411
Динамическое масштабирование частоты 411
Одновременная многопоточность 412
Изменение частоты 413
Привязка к ядру процессора 413
Приоритет процесса 414
Приложение B. Включение больших страниц 415
Windows 415
Linux 416
Явные большие страницы 416
Прозрачные большие страницы 417
Приложение C. Трассировка процессоров Intel 419
Процесс работы 419
Временные пакеты 421
Сбор и декодирование трасс 421
Дисковое пространство и время декодирования 423
Инструменты 424
Intel PT: ссылки и упоминания 424
Приложение D. Анализ трассировки для Windows 425
Инструменты для записи трасс ETW 425
Инструменты для просмотра и анализа трасс ETW 426
Практический пример — медленный старт программы 426
Установка 426
Захват трассы 427
Анализ в WPA 428
