2013-04-26 2 views
6

Напишите программу и попробуйте сравнить (измерить, если можно) время доступа к данным из основной памяти и кеша.Как написать программу на C для измерения скорости кеша?

Если вы можете это сделать, то как измерить скорость каждого уровня кеша?

+3

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

+0

возможно использовать регистры и mmap? Но это кажется очень субъективным (кроме этого есть другие процессы, запущенные на компьютере). Похоже на то, что должно быть сделано на аппаратном уровне; в противном случае другие потоки/процессы/OS-материал окажутся на пути – cegfault

+0

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

ответ

3

Как правило, это требует некоторого знания «геометрии» кэш-памяти и другой его аспектах. Также полезно иметь некоторый контроль над системой за пределы простого доступа пользователя к ней и зависящим от реализации вещам, таким как более тонкое время, чем может быть поставлено через стандартный механизм C clock.

Вот первоначальный подход:

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

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

Вот некоторые причины такой подход является неадекватным:

  • Он не контролирует инструкции, которые используются для чтения или записи кэш-памяти. Компилятор C может хорошо генерировать инструкции слова загрузки и хранения, но многие современные процессоры имеют инструкции, которые могут загружать и хранить 16 байтов за раз, а чтение и запись могут выполняться быстрее с этими инструкциями, чем с четырехбайтовыми командами слова.
  • Кэш будет вести себя по-разному, когда вы будете получать доступ последовательно, чем если бы вы случайно получили доступ к нему. Большинство кэшей делают некоторую попытку отслеживать, когда используются данные, так что недавно использованные данные хранятся в кеше, в то время как другие данные выдаются. Части доступа к реальным программам обычно отличаются от описанных выше последовательных операций.
  • В частности, последовательные записи в память могут заполнять всю строку кэша, так что ничего не нужно читать из памяти, тогда как шаблон использования в реальном мире, который записывает только одно слово в конкретное местоположение, возможно, должен быть реализуется путем чтения строки кэша из памяти и слияния в измененных байтах.
  • Конкурс от других процессов в вашей системе будет мешать тому, что находится в кеше и с измерением.
5

Вам нужно придумать эвристику, которая заставит пропустить кеш на 100% (или очень близкую) (надеюсь, у вас есть код отказа от кэширования?) И 100% -ный кэш. Hooray, который работает для 1 уровня кеша. Теперь, как сделать то же самое для уровня 2 и 3?

Со всей серьезностью, то, вероятно, не способ сделать это на 100% надежно без специальных аппаратных средств и следов, подключенных к CPU и памяти, но вот что я хотел бы сделать:

Написать «букет» из материал в 1 место в памяти - достаточно, чтобы вы могли быть уверены, что он последовательно кладет L1-кеш и записывает время (что влияет на ваш кеш, так что будьте осторожны). Вы должны сделать этот набор записей без ветвей, чтобы попытаться избавиться от несоответствий прогноза ветвления. Это лучшее время. Теперь, каждый так часто, записывайте данные о кеш-строке в случайное удаленное местоположение в ОЗУ в конце вашего известного местоположения и записывайте новое время. Надеюсь, это займет больше времени. Продолжайте делать эту запись в разное время, и, надеюсь, вы увидите пару таймингов, которые обычно группируются. Каждая из этих групп «может» показывать тайминги для L2, L3 и таймингов доступа к памяти. Проблема в том, что есть много других вещей, которые мешают. ОС может контекст переключить вас и испортить кеш. Прерывание может прийти и через ваше время отключить. Будет много вещей, которые могли бы выбросить ценности. Но, надеюсь, вы получите достаточный сигнал в своих данных, чтобы узнать, работает ли он.

Это, вероятно, было бы проще сделать в более простой, внедренной системе типов, где ОС (если есть) не будет мешать вам.

+0

Но как измерить время считывания данных один раз? Это так мало и может быть всего несколько нс! – Sayakiss

+0

Делая это достаточно времени. Вы должны иметь возможность получить счет в миллисекунду. Тем не менее, я не сказал, что это будет легко :) –

+0

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

2

Взгляните на cachegrind-valgrind:

похожий на Cachegrind имитирует, как программа взаимодействует с кэш- иерархией машины и (необязательно) филиалом предсказателем. Он имитирует машину с независимыми инструкциями первого уровня и кэшами данных (I1 и D1), , поддерживаемыми унифицированным кэшем второго уровня (L2). Это точно соответствует конфигурации многих современных машин.

См Теза хороших вопросы, они какие-то образом связанные с:

  1. How do I programmatically disable hardware prefetching?
  2. How would you generically detect cache line associativity from user mode code?
  3. How to invalidate cache when benchmarking?
+1

Ах, эмуляция может быть лучшим вариантом, если качество эмуляции достаточно хорошее. Хорошая идея. –

Смежные вопросы