Да, свойства объединения и объединения записей LFB поддерживают все типы памяти, кроме типа UC.Вы можете наблюдать их влияние экспериментально, используя следующую программу.В качестве входных данных он принимает два параметра:
STORE_COUNT
: число 8-байтовых хранилищ для последовательной работы. INCREMENT
: шаг между последовательными хранилищами.
Существует 4 различных значения INCREMENT
, которые особенно интересны:
- 64: все хранилища выполняются на уникальных строках кэша.Объединение и объединение записей не будут иметь эффекта.
- 0: все хранилища находятся в одной строке кэша и в одном и том же месте в этой строке.В этом случае вступает в силу объединение операций записи.
- 8: Каждые 8 последовательных хранилищ находятся в одной строке кэша, но в разных местах этой строки.В этом случае вступает в силу объединение записи.
- 4: целевые местоположения последовательных хранилищ перекрываются в одной и той же строке кэша.Некоторые магазины могут пересекать две строки кэша (в зависимости от
STORE_COUNT
).И объединение записи, и объединение будут иметь эффект.
Существует еще один параметр, ITERATIONS
, который используется для многократного повторения одного и того же эксперимента для проведения надежных измерений.Вы можете сохранить его на уровне 1000.
%define ITERATIONS 1000
BITS 64
DEFAULT REL
section .bss
align 64
bufsrc: resb STORE_COUNT*64
section .text
global _start
_start:
mov ecx, ITERATIONS
.loop:
; Flush all the cache lines to make sure that it takes a substantial amount of time to fetch them.
lea rsi, [bufsrc]
mov edx, STORE_COUNT
.flush:
clflush [rsi]
sfence
lfence
add rsi, 64
sub edx, 1
jnz .flush
; This is the main loop where the stores are issued sequentially.
lea rsi, [bufsrc]
mov edx, STORE_COUNT
.inner:
mov [rsi], rdx
sfence ; Prevents potential combining in the store buffer.
add rsi, INCREMENT
sub edx, 1
jnz .inner
; Spend sometime doing nothing so that all the LFBs become free for the next iteration.
mov edx, 100000
.wait:
lfence
sub edx, 1
jnz .wait
sub ecx, 1
jnz .loop
; Exit.
xor edi,edi
mov eax,231
syscall
Я рекомендую следующую настройку:
- Отключите все аппаратные средства предварительной выборки, используя
sudo wrmsr -a 0x1A4 0xf
.Это гарантирует, что они не будут мешать (или иметь минимальные помехи) экспериментам. - Установите частоту ЦП на максимум.Это увеличивает вероятность того, что основной цикл будет полностью выполнен до того, как первая строка кэша достигнет L1, и приведет к освобождению LFB.
- Отключите гиперпоточность, поскольку LFB совместно используются (по крайней мере, после Sandy Bridge, но нена всех микроархитектурах).
Счетчик производительности L1D_PEND_MISS.FB_FULL
позволяет нам фиксировать эффект объединения записей в отношении того, как он влияет на доступность LFB.Это поддерживается на Intel Core и позже.Он описывается следующим образом:
Количество раз, когда запросу требовалась запись FB (Fill Buffer), но для нее не было доступной записи.Запрос включает в себя кэшируемые / не кэшируемые требования, которые являются инструкциями загрузки, сохранения или предварительной выборки SW.
Сначала запустите код без внутреннего цикла и убедитесь, что L1D_PEND_MISS.FB_FULL
равен нулю, что означает цикл очисткине влияет на количество событий.
На следующем рисунке показано STORE_COUNT
против общего числа L1D_PEND_MISS.FB_FULL
, разделенного на ITERATIONS
.
Мы можем наблюдать следующее:
- Ясно, что существует ровно 10 LFB.
- Когда возможно объединение или объединение записи,
L1D_PEND_MISS.FB_FULL
равно нулю для любого числаstore. - Когда длина шага составляет 64 байта,
L1D_PEND_MISS.FB_FULL
больше нуля, когда количество хранилищ больше 10.
Позже у вас есть это "[WC] особенно важен для записи в некэшированную память », что явно противоречит« не относится к части UC ».
И WC, и UC классифицируются как не кэшируемые.Таким образом, вы можете соединить два оператора, чтобы сделать вывод, что WC особенно важен для записи в память WC.
См. Также: Где находится объединяющий запись буфер?x86 .