Что важно при оптимизации для кеша процессора (в C)?

13

Читая эти два вопроса , я вижу, что понимание поведения кэширования процессора может быть важным при работе с большими объемами данных в памяти. Я хотел бы понять, как работает кэширование, чтобы добавить еще один инструмент в мой набор инструментов оптимизации.

Каковы основные принципы работы кэша ЦП, чтобы я мог писать код, который использует его разумно? Кроме того, есть ли способ профилировать код, чтобы увидеть, замедляет ли плохое использование кэша?

Тимоти Джонс
источник
Кеши не везде одинаковы; Очевидно, они различаются по размеру. Не ждите, чтобы узнать какие-либо глубокие секреты, только хорошие практики (как совет Майкла Боргвардта).
Дэвид Торнли

Ответы:

17
  • Держите ваши данные маленькими, если это возможно
  • Храните вещи, которые будут доступны вместе (или сразу после другого) рядом друг с другом в памяти
  • Узнайте о параметрах оптимизации вашего компилятора
  • Прочтите, что каждый программист должен знать о памяти, чтобы узнать больше подробностей, чем вы когда-либо хотели
Майкл Боргвардт
источник
+1 за «Держите вещи, которые будут доступны вместе рядом друг с другом»; это тот, который легко забыть.
Donal Fellows
И скажи компилятору оптимизировать.
вправо
@WTP: справа - добавлено.
Майкл Боргвардт
Кроме того, держите мьютексы хорошо разделенными. Изменение мьютекса (должно) очищать все строки кэша, в которых он находится, на всех процессорах. Это может сильно повлиять на производительность, если вам удалось получить 2-3 мьютекса в одной строке кэша.
Ватине
12

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

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

Ниже приведена ссылка, опубликованная Ларри OBrien в одном из его ответов .

http://onward-conference.org/2011/images/Pueschel_2011_AutomaticPerformanceProgramming_Onward11.pdf

rwong
источник
2
самая быстрая реализация BLAS (GotoBLAS) использует оптимизированный вручную код, чтобы обеспечить максимальное использование кэша для умножения матриц
quant_dev
2

Вполне возможно понять и оптимизировать кэши. Это начинается с понимания аппаратного обеспечения и продолжается контролем системы. Чем меньше у вас контроля над системой, тем меньше вероятность успеха. Linux или Windows работают с множеством приложений / потоков, которые не работают.

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

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

Вы можете легко сделать кэш бесполезным, если не будете тщательно управлять своей памятью. Например, если у вас есть несколько блоков данных, которые вы обрабатываете, надеясь сохранить их в кеше, но они находятся в памяти по адресам, которые даже кратны относительно проверки попадания / пропуска кэшей, скажем, 0x10000 0x20000 0x30000, и у вас есть больше Эти способы могут привести к очень быстрому созданию чего-то, что работает довольно медленно при включенном кеше, медленнее, чем при отключенном. Но измените это на 0x10000, 0x21000, 0x32000, и этого может быть достаточно, чтобы в полной мере воспользоваться кешем, уменьшая выселения.

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

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

Старожил
источник
1

Оба nwong - х и Майкл Borgwardt в ответ дать хороший совет.

Кроме того, сначала доверьтесь оптимизации компилятора по этим вопросам.

Если вы используете недавний компилятор GCC, вы можете использовать (с экономией) его __builtin_prefetchфункцию. Смотрите этот ответ на stackoverflow.

Василий Старынкевич
источник