C ++ кэш-программирование - PullRequest
       102

C ++ кэш-программирование

56 голосов
/ 17 декабря 2009

Есть ли способ в C ++ определить размер кэша процессора? У меня есть алгоритм, который обрабатывает много данных, и я хотел бы разбить эти данные на куски так, чтобы они помещались в кэш. Это возможно? Можете ли вы дать мне другие советы по программированию с учетом размера кэша (особенно в отношении обработки многопоточных / многоядерных данных)?

Спасибо!

Ответы [ 11 ]

15 голосов
/ 24 декабря 2009

Согласно « Что должен знать каждый программист о памяти », Ульрих Дреппер может сделать в Linux следующее:

Как только у нас есть формула для памяти Требование мы можем сравнить его с размер кэша. Как упоминалось ранее, кеш может быть разделен с несколькими другие ядра. В настоящее время {Там определенно скоро будет лучший способ!} единственный способ получить правильная информация без жесткого кодирования знание через / sys файловая система. В таблице 5.2 мы видели о чем публикует ядро аппаратное обеспечение. Программа должна найти каталог:

/sys/devices/system/cpu/cpu*/cache

Это указано в Раздел 6: Что могут сделать программисты .

Он также описывает короткий тест прямо под рисунком 6.5, который можно использовать для определения размера кэша L1D, если вы не можете получить его из ОС.

Есть еще одна вещь, с которой я столкнулся в его статье: sysconf(_SC_LEVEL2_CACHE_SIZE) - это системный вызов в Linux, который должен возвращать размер кэша L2, хотя он не выглядит хорошо документированным.

11 голосов
/ 17 декабря 2009

C ++ сам по себе не «заботится» о кешах ЦП, поэтому он не поддерживает запросы к размеру кеша, встроенному в язык. Если вы разрабатываете для Windows, то есть GetLogicalProcessorInformation () - функция , которую можно использовать для запроса информации о кешах процессора.

8 голосов
/ 30 августа 2010

Предварительно выделить большой массив. Затем получите доступ к каждому элементу последовательно и запишите время для каждого доступа. В идеале, когда пропадет кеш, будет скачок времени доступа. Затем вы можете рассчитать свой кэш L1. Это может не сработать, но стоит попробовать.

4 голосов
/ 24 февраля 2013

Вы можете увидеть эту тему: http://software.intel.com/en-us/forums/topic/296674

Краткий ответ в этой другой теме:

На современном оборудовании IA-32 размер строки кэша равен 64. Значение 128 равно наследие микроархитектуры Intel Netburst (например, Intel Pentium D) где 64-байтовые строки соединены в 128-байтовые сектора. Когда линия в секторе выбирается, оборудование автоматически выбирает другой линия в секторе тоже. Таким образом, с точки зрения ложного обмена, эффективный размер строки на процессорах Netburst составляет 128 байт. (http://software.intel.com/en-us/forums/topic/292721)

4 голосов
/ 30 августа 2010

Интересно, что я написал программу для этого некоторое время назад (хотя в C, но я уверен, что это будет легко включить в код C ++).

http://github.com/wowus/CacheLineDetection/blob/master/Cache%20Line%20Detection/cache.c

Интересна функция get_cache_line, которая возвращает местоположение прямо перед самым большим всплеском временных данных доступа к массиву. Это правильно угадано на моей машине! Если что-нибудь еще, это может помочь вам сделать свой собственный.

Это основано на этой статье, которая изначально пробудила во мне интерес: http://igoro.com/archive/gallery-of-processor-cache-effects/

4 голосов
/ 17 декабря 2009

В зависимости от того, что вы пытаетесь сделать, вы также можете оставить это какой-то библиотеке. Поскольку вы упоминаете многоядерную обработку, вы можете взглянуть на Intel Threading Building Blocks .

TBB включает в себя распределители памяти с кеш-памятью. В частности, отметьте cache_aligned_allocator (в справочной документации я не нашел прямой ссылки).

4 голосов
/ 17 декабря 2009

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

1 голос
/ 03 ноября 2013

IIRC, GCC имеет подсказку __builtin_prefetch.

http://gcc.gnu.org/onlinedocs/gcc-3.3.6/gcc/Other-Builtins.html

имеет отличный раздел по этому вопросу. В основном, это предлагает:

__builtin_prefetch (&array[i + LookAhead], rw, locality);

, где rw - это значение 0 (подготовка к чтению) или 1 (подготовка к записи), а locality использует число 0-3, где ноль - это не локальность и 3 очень сильный населенный пункт.

Оба являются необязательными. LookAhead - это количество элементов, к которым можно заглянуть. Если бы доступ к памяти составлял 100 циклов, а развернутые циклы были разнесены на два цикла, LookAhead можно было бы установить на 50 или 51.

0 голосов
/ 05 июня 2019

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

Определение размера кэша во время компиляции

Для некоторых приложений вы знаете точную архитектуру, на которой будет выполняться ваш код, например, если вы можете скомпилировать код непосредственно на хост-машине. В этом случае упростить поиск размера и жесткое кодирование - это вариант (может быть автоматизирован в системе сборки). На большинстве современных машин строка кэша L1 должна составлять 64 байта.

Если вы хотите избежать этой сложности или вам нужна поддержка компиляции на неизвестных архитектурах, вы можете использовать функцию C ++ 17 std :: hardware_constructive_interference_size в качестве хорошего запасного варианта. Он предоставит оценку времени компиляции для строки кэша, но помнит о его ограничениях . Обратите внимание, что компилятор не может точно угадать, когда он создает двоичный файл, поскольку размер строки кэша, как правило, зависит от архитектуры.

Определение размера кэша во время выполнения

Во время выполнения у вас есть преимущество в том, что вы знаете точную машину, но вам потребуется код для конкретной платформы, чтобы прочитать информацию из ОС. Хорошей отправной точкой является фрагмент кода из этого ответа , который поддерживает основные платформы (Windows, Linux, MacOS). Аналогичным образом вы также можете прочитать размер кэша L2 во время выполнения.

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

Объединение обоих подходов

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

0 голосов
/ 04 июня 2019

В C ++ 17 вы можете использовать std :: hardware_destructive_interference_size для определения размера кэша L1. Смотри https://en.cppreference.com/w/cpp/thread/hardware_destructive_interference_size Насколько я знаю, он поддерживается только Microsoft Visual Studio 2019 на данный момент.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...