Кэш предназначен для уменьшения количества раз, которое ЦП останавливает в ожидании выполнения запроса памяти (избегая памяти задержка ), и, как второй эффект, возможно, для уменьшения общего объема данных, которые необходимо передать (сохранение памяти пропускная способность ).
Методы, позволяющие избежать страданий от задержек при извлечении памяти, как правило, являются первыми вещами, которые необходимо учитывать, и иногда помогают в дальнейшем. Ограниченная пропускная способность памяти также является ограничивающим фактором, особенно для многоядерных и многопоточных приложений, где многие потоки хотят использовать шину памяти. Другой набор методов помогает решить последнюю проблему.
Улучшение пространственная локальность означает, что вы гарантируете, что каждая строка кэша используется полностью после ее сопоставления с кэшем. Когда мы посмотрели на различные стандартные тесты, мы увидели, что удивительно большая часть из них не использует 100% извлеченных строк кэша до того, как строки кэша будут удалены.
Улучшение использования строки кэша помогает в трех отношениях:
- Он имеет тенденцию помещать более полезные данные в кеш, существенно увеличивая эффективный размер кеша.
- Он имеет тенденцию помещать более полезные данные в одну и ту же строку кэша, увеличивая вероятность того, что запрошенные данные могут быть найдены в кэше.
- Это уменьшает требования к пропускной способности памяти, так как выборок будет меньше.
Общие методы:
- Используйте меньшие типы данных
- Организуйте свои данные, чтобы избежать дыр в выравнивании (сортировка элементов структуры по уменьшению размера осуществляется в одну сторону)
- Остерегайтесь стандартного распределителя динамической памяти, который может создавать дыры и распространять ваши данные в памяти при нагревании.
- Убедитесь, что все смежные данные действительно используются в горячих циклах. В противном случае рассмотрите возможность разбиения структур данных на горячие и холодные компоненты, чтобы горячие циклы использовали горячие данные.
- избегайте алгоритмов и структур данных, которые демонстрируют нерегулярные схемы доступа, и предпочитают линейные структуры данных.
Следует также отметить, что есть и другие способы скрыть задержку памяти, кроме использования кэшей.
Современные ЦП: у них часто есть один или несколько аппаратных предварительных загрузчиков . Они тренируются по промахам в тайнике и пытаются выявить закономерности. Например, после нескольких пропусков в последующих строках кеша, средство предварительной выборки hw начнет извлекать строки кеша в кеш, ожидая потребностей приложения. Если у вас есть обычный шаблон доступа, аппаратный предварительный выборщик обычно делает очень хорошую работу. И если ваша программа не отображает обычные шаблоны доступа, вы можете улучшить ситуацию, добавив инструкции предварительной выборки самостоятельно.
Перегруппировав инструкции таким образом, чтобы те, которые всегда пропускали в кеше, находились близко друг к другу, ЦП иногда может перекрывать эти выборки, так что приложение выдерживает только одну задержку ( Параллелизм уровня памяти ) .
Чтобы уменьшить общее давление на шину памяти, вы должны начать обращаться к так называемой временной локализации . Это означает, что вам необходимо повторно использовать данные, пока они еще не были удалены из кэша.
Объединение циклов, которые касаются одних и тех же данных ( слияние циклов ), и использование методов перезаписи, известных как tiling или блокирование , все стремятся избежать этих дополнительных выборок памяти .
Несмотря на то, что для этого упражнения по переписке есть несколько практических правил, вам обычно нужно тщательно учитывать зависимости данных, переносимых циклами, чтобы не влиять на семантику программы.
Это то, что действительно окупается в многоядерном мире, где вы, как правило, не увидите значительных улучшений пропускной способности после добавления второго потока.