Подтвердить что ты не робот

Как процессоры Intel Xeon записываются в память?

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

Если процессор записывает только измененные 8 байтов в память, тогда первый алгоритм использует гораздо меньшую пропускную способность памяти: 8 байт против 192 байт. Если ЦП пишет целые строки кэша, разница между 128 и 192 байтами менее впечатляющая.

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

Как я понимаю, записи идут в буфер хранилища, а затем в кеш. Они могут быть записаны только в память, когда грязная строка кеша выведена из кеша, но разве Intel отслеживает, какие части строки кэша грязны, или просто сбрасывает все это? Я скорее сомневаюсь, что они отслеживают вещи ниже детализации кеш-строки. Я также был бы очень удивлен, если что-нибудь пойдет в память до выключения линии кэша.

4b9b3361

Ответ 1

Локальность имеет значение даже для самой DRAM, даже при дисконтировании кэширования. Пакетная запись 64B смежных байтов для грязной линии кэша выполняется намного быстрее, чем 16 записей с 4 до 16 разных адресов. Или, говоря иначе, запись всей строки кэша не намного медленнее, чем запись только нескольких измененных байтов в строке кэша.

Что каждый программист должен знать о памяти, Ульрих Дреппер, объясняет много вещей об избежании узких мест в памяти при программировании. Он включает некоторые детали адресации DRAM. Контроллеры DRAM должны выбрать строку, а затем выбрать столбец. Доступ к другой странице виртуальной памяти также может привести к пропуску TLB.

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

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

Существуют так называемые невременные чтения/записи (movnti/movntdqa), которые обходят кеш. Они предназначены для использования с данными, которые не будут затронуты до тех пор, пока они все равно не будут выселены из кеша (следовательно, невременные). Это плохая идея для данных, которые могут извлечь выгоду из кеширования, но позволят вам записать 4 байта в память, а не целую строку кэша. В зависимости от MTRR для этого диапазона памяти запись может или не может быть связана с записью. (Это относится к областям ввода-вывода с отображением памяти, где две соседние записи 4B не совпадают с одной записью 8B.)

Алгоритм, который касается только двух линий кэша, безусловно, имеет преимущество на этом счету, если только он не требует гораздо большего вычисления или особенно ветвления, чтобы определить, какую память писать. Может быть, задайте другой вопрос, если вы хотите помочь решить. (см. ссылки в fooobar.com/tags/x86/..., esp Agner Fog guide, для информации, которая поможет вам самим решить.)

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

Ответ 2

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

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

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