Я пытаюсь понять поведение uop-кеша (DSB в intel docs) на моем чипе Haswell. Я основываюсь на руководстве по оптимизации Intel и PDF-файлах Agner.
Я обнаружил несколько случаев, когда интерфейс надежно возвращается к декодеру MITE в зависимости от небольших изменений в коде, что приводит меня в замешательство. .
Пример этого выглядит так (в gnu как -msyntax=intel
):
mov rax, 100000000
.align 64
1:
// DSB-cacheable nops to
// overflow LSD
.fill 12, 1, 0x90
.align 32
.fill 12, 1, 0x90
.align 32
.fill 12, 1, 0x90
.align 32
.fill 12, 1, 0x90
.align 32
// this first block should fill up way 1 of our uop-cache set
add ecx, ecx
nop
nop
nop
add ecx, ecx
add ecx, ecx
// way 2
add ecx, ecx
add ecx, ecx
add ecx, ecx
nop
add ecx, ecx
add ecx, ecx
// way 3
or ecx, ecx
or ecx, ecx // <---- an example of offending instruction
or ecx, ecx
or ecx, ecx
or ecx, ecx
or ecx, ecx // <---- this one as well
// next uop set
dec rax
jnz 1b
Очевидно, что это бессмысленный пример. Я обычно включаю его как часть al oop, содержащего достаточно других 32-байтовых блоков, чтобы переполнить LSD, чтобы сделать вещи проще, но это не требуется AFAICT. По тем же причинам я сделал этот блок ровно 32 байта, чтобы исключить все, что связано с висячими инструкциями.
Я измеряю использование DSB против MITE, используя два соответствующих счетчика perf (IDQ.MITE_UOPS и IDQ.DSB_UOPS).
Как написано, этот 32-байтовый блок будет кэшироваться в DSB, однако для запуска устаревшего декодера достаточно заменить один из отмеченных or ecx, ecx
на add ecx, ecx
.
Это удивляет меня, потому что обе инструкции имеют одинаковый размер и обе генерируют 1 моп.
На самом деле, играя с подобными примерами, единственная общая точка , которую я нашел между командами, которые запускают или не запускают различные операции кэширования, находится , независимо от того, будут ли они макрокомбинироваться с ветвями, если они есть.
Я не могу найти описание этого (или какое-либо связанное) поведение где-нибудь, я что-то упускаю?