Как написать программу для кеширования дружественной программы на C++?

Недавно Херб Саттер выступил с великолепной лекцией на тему "Современный C++: что нужно знать". Основной темой этого доклада была эффективность и то, как локальность данных и доступ к памяти имеют значение. Он также объяснил, как процессор будет любить линейный доступ к памяти (массив / вектор). В этой теме он взял один пример из другого классического справочника "Производительность игры Боба Нистрома".

Прочитав эти статьи, я понял, что существует два типа кеша, которые влияют на производительность программы:

  1. Кэш данных
  2. Кэш инструкции

Инструмент Cachegrind также измеряет информацию об инструментах типа кэша нашей программы. Первые пункты были объяснены во многих статьях / блогах и о том, как добиться хорошей эффективности кэширования данных (локальность данных).

Однако я не получил много информации по теме " Кэш инструкций" и о том, что мы должны позаботиться в нашей программе, чтобы добиться лучшей производительности? Насколько я понимаю, мы (программист) не имеем большого контроля над тем, какая инструкция или какой порядок будет выполняться.

Было бы здорово, если бы маленькие программы на C++ объяснили, как этот счетчик (кэш инструкций.ie) будет меняться в зависимости от нашего стиля написания программ. Каким лучшим практикам следует следовать, чтобы достичь лучшей производительности в этом направлении?

Я имею в виду, что мы можем понять о темах кеширования данных, если наша программа (вектор против списка) аналогичным образом позволяет объяснить о 2-м пункте. Основная цель этого вопроса - как можно лучше понять эту тему.

1 ответ

Решение

Любой код, который изменяет поток выполнения, влияет на кэш инструкций. Это включает вызовы функций и циклы, а также разыменование указателей на функции.

Когда выполняется команда перехода или перехода, процессор должен потратить дополнительное время, решая, находится ли код в кэше команд или ему необходимо перезагрузить кэш команд (из места назначения ветви).

Например, некоторые процессоры могут иметь достаточно большой кэш команд для хранения кода выполнения для маленьких циклов. Некоторые процессоры не имеют большого кеша команд и просто перезагружают его. Перезагрузка кэша команд занимает время, которое может быть потрачено на выполнение инструкций.

Поиск по этим темам:

  • Разматывание петли
  • Условное выполнение инструкций (доступно на процессорах ARM)
  • Встроенные функции
  • Инструкция трубопровода

Редактировать 1: методы программирования для повышения производительности
Для повышения производительности и уменьшения перезагрузки кэша команд выполните следующие действия:

Сокращение выражений "если" Создайте свой код, чтобы минимизировать операторы "если". Это может включать булеву алгебру, использование математики или упрощение сравнений (действительно ли они нужны?). Предпочитаю уменьшать содержание предложений "then" и "else", чтобы компилятор мог использовать инструкции языка условной ассемблера.

Определите маленькие функции как встроенные или макросы
С вызовом функций связаны накладные расходы, такие как сохранение местоположения возврата и перезагрузка кэша команд. Для функций с небольшим количеством операторов попробуйте предложить компилятору сделать их встроенными. Встраивание означает вставку содержимого кода, где выполняется, а не вызов функции. Поскольку избегается вызов функции, возникает необходимость перезагрузить кэш команд.

Развернуть петли
Для небольших итераций не зацикливайтесь, а повторяйте содержимое цикла (некоторые компиляторы могут делать это при более высоких настройках уровня оптимизации). Чем больше контента повторяется, тем меньше количество веток к началу цикла и тем меньше нужно перезагрузить кэш команд.

Используйте поиск в таблице, а не операторы "если"
Некоторые программы используют лестницы "если-еще-если" для отображения данных на значения. Каждый оператор "if" является перерывом в выполнении в кэше команд. Иногда, с небольшой математикой, значения могут быть помещены в таблицу как массив, и индекс вычисляется математически. Как только индекс известен, процессор может извлечь данные, не нарушая кеш инструкций.

Изменить данные или структуры данных
Если тип данных является постоянным, программа может быть оптимизирована вокруг данных. Например, программа, обрабатывающая пакеты сообщений, может основывать свои операции на основе идентификаторов пакетов (представьте массив указателей функций). Функции будут оптимизированы для обработки пакетов.

Измените связанные списки на массивы или другой контейнер с произвольным доступом. К элементам массива можно обращаться с помощью математики, а не выполнения прерываний. Связанные списки должны быть просмотрены (цикл), чтобы найти элемент.

Другие вопросы по тегам