НАБЛЮДЕНИЕ 1: Ветвь с целью в той же 32-байтовой области, которая, как ожидается, будет взята, во многом похожа на безусловную ветвь с точки зрения кэша мопов (т.е. это должен быть последний моп в строка).
Рассмотрим следующую реализацию inhibit_uops_cache
:
align 32
inhibit_uops_cache:
xor eax, eax
jmp t1 ;jz, jp, jbe, jge, jle, jnb, jnc, jng, jnl, jno, jns, jae
t1:
jmp t2 ;jz, jp, jbe, jge, jle, jnb, jnc, jng, jnl, jno, jns, jae
t2:
jmp t3 ;jz, jp, jbe, jge, jle, jnb, jnc, jng, jnl, jno, jns, jae
t3:
dec rdi
ja inhibit_uops_cache
ret
Код протестирован для всех веток, упомянутых в комментарии. Разница оказалась очень незначительной, поэтому я предоставляю только 2 из них:
jmp:
Performance counter stats for './bin':
4 748 772 552 idq.dsb_cycles (57,13%)
7 499 524 594 idq.dsb_uops (57,18%)
5 397 128 360 idq.mite_uops (57,18%)
8 696 719 idq.ms_uops (57,18%)
6 247 749 210 dsb2mite_switches.penalty_cycles (57,14%)
3 841 902 993 frontend_retired.dsb_miss (57,10%)
21 508 686 982 cycles (57,10%)
5,464493212 seconds time elapsed
5,464369000 seconds user
0,000000000 seconds sys
jge:
Performance counter stats for './bin':
4 745 825 810 idq.dsb_cycles (57,13%)
7 494 052 019 idq.dsb_uops (57,13%)
5 399 327 121 idq.mite_uops (57,13%)
9 308 081 idq.ms_uops (57,13%)
6 243 915 955 dsb2mite_switches.penalty_cycles (57,16%)
3 842 842 590 frontend_retired.dsb_miss (57,16%)
21 507 525 469 cycles (57,16%)
5,486589670 seconds time elapsed
5,486481000 seconds user
0,000000000 seconds sys
IDK, почему число операций dsb составляет 7 494 052 019
, что значительно меньше, чем 4096 * 4096 * 128 * 4 = 8 589 934 592
.
Замена любого из jmp ветвью, которая, как ожидается, не будет взята дает результат, который значительно отличается. Например:
align 32
inhibit_uops_cache:
xor eax, eax
jnz t1 ; perfectly predicted to not be taken
t1:
jae t2
t2:
jae t3
t3:
dec rdi
ja inhibit_uops_cache
ret
приводит к следующим счетчикам:
Performance counter stats for './bin':
5 420 107 670 idq.dsb_cycles (56,96%)
10 551 728 155 idq.dsb_uops (57,02%)
2 326 542 570 idq.mite_uops (57,16%)
6 209 728 idq.ms_uops (57,29%)
787 866 654 dsb2mite_switches.penalty_cycles (57,33%)
1 031 630 646 frontend_retired.dsb_miss (57,19%)
11 381 874 966 cycles (57,05%)
2,927769205 seconds time elapsed
2,927683000 seconds user
0,000000000 seconds sys
Рассматривая другой пример, аналогичный CASE 1 :
align 32
inhibit_uops_cache:
nop
nop
nop
nop
nop
xor eax, eax
jmp t1
t1:
dec rdi
ja inhibit_uops_cache
ret
приводит к
Performance counter stats for './bin':
6 331 388 209 idq.dsb_cycles (57,05%)
19 052 030 183 idq.dsb_uops (57,05%)
343 629 667 idq.mite_uops (57,05%)
2 804 560 idq.ms_uops (57,13%)
367 020 dsb2mite_switches.penalty_cycles (57,27%)
55 220 850 frontend_retired.dsb_miss (57,27%)
7 063 498 379 cycles (57,19%)
1,788124756 seconds time elapsed
1,788101000 seconds user
0,000000000 seconds sys
jz:
Performance counter stats for './bin':
6 347 433 290 idq.dsb_cycles (57,07%)
18 959 366 600 idq.dsb_uops (57,07%)
389 514 665 idq.mite_uops (57,07%)
3 202 379 idq.ms_uops (57,12%)
423 720 dsb2mite_switches.penalty_cycles (57,24%)
69 486 934 frontend_retired.dsb_miss (57,24%)
7 063 060 791 cycles (57,19%)
1,789012978 seconds time elapsed
1,788985000 seconds user
0,000000000 seconds sys
jno:
Performance counter stats for './bin':
6 417 056 199 idq.dsb_cycles (57,02%)
19 113 550 928 idq.dsb_uops (57,02%)
329 353 039 idq.mite_uops (57,02%)
4 383 952 idq.ms_uops (57,13%)
414 037 dsb2mite_switches.penalty_cycles (57,30%)
79 592 371 frontend_retired.dsb_miss (57,30%)
7 044 945 047 cycles (57,20%)
1,787111485 seconds time elapsed
1,787049000 seconds user
0,000000000 seconds sys
Все эти эксперименты заставили меня думать, что наблюдение соответствует реальному поведению кэша мопов. Я также провел еще один эксперимент и, судя по счетчикам br_inst_retired.near_taken
и br_inst_retired.not_taken
, результат коррелирует с наблюдением.
Рассмотрим следующую реализацию inhibit_uops_cache
:
align 32
inhibit_uops_cache:
t0:
;nops 0-9
jmp t1
t1:
;nop 0-6
dec rdi
ja t0
ret
Собирая dsb2mite_switches.penalty_cycles
и frontend_retired.dsb_miss
имеем:
Ось X графика обозначает число nop
s, например, 24 означает 2 nop
s после метки t1
, 4 nop
s после метки t0
:
align 32
inhibit_uops_cache:
t0:
nop
nop
nop
nop
jmp t1
t1:
nop
nop
dec rdi
ja t0
ret
Судя по графикам, к которым я пришел
НАБЛЮДЕНИЕ 2: В случае если в пределах 32-байтовой области есть 2 ветви, которые, как предполагается, должны быть заняты, нет заметной корреляции между переключателями dsb2mite
и пропусками DSB. Таким образом, промахи DSB могут происходить независимо от переключателей dsb2mite
.
Увеличение скорости frontend_retired.dsb_miss
хорошо коррелирует с увеличением скорости idq.mite_uops
и уменьшением idq.dsb_uops
. Это можно увидеть на следующем графике:
НАБЛЮДЕНИЕ 3: Происходит промах DSB по какой-то (неясной?) Причине приводит к появлению пузырьков IDQ и, следовательно, к потере RAT.
Вывод: Принимая во внимание все измерения, безусловно, существуют некоторые различия между поведением, определенным в Intel Optimization Manual, 2.5.2.2 Decoded ICache