uop缓存的小姐粒度

问题描述 投票:1回答:1

英特尔优化手册/ B.5.7.3

解码的ICache中没有部分匹配。如果有任何微操作是缺少对32字节块的查找的一部分,已解码该交易的所有微操作都会发生ICache丢失]

uop-cache丢失是否真的以32字节粒度发生?

assembly x86 x86-64 cpu-architecture
1个回答
1
投票

KbL i7-8550U上,其行为就像每个高速缓存行没有部分命中,不是32字节区域

我实际上进行了下面描述的更多不同的实验,但是在这里不可能全部适合它们。


《英特尔优化手册》证明uop缓存包含L1i:

解码的ICache实际上包含在指令缓存中,ITLB。

考虑以下内容

示例1。

;edi = 1 << 31
align 32
test_uop_cache_hit:
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 

    ;More 8 * nop ax blocks

    dec edi
    jnz test_uop_cache_hit
    ret

收集计数器icache_64b.iftag_hitidq.dsb_uopsidq.mite_uops,下面的图

enter image description here

uops图是合理的。所有uops均从dsb交付。

第一张图显示,每个L1i高速缓存行只有一个标签查找,大小为64字节。标签查找对于找到uop缓存条目是必需的。

示例2。

在同一高速缓存行的8 * nop ax个块的中间添加jmp。

;edi = 1 << 31
align 64
test_uop_cache_hit:
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    jmp test_uop_cache_hit_1

align 32
test_uop_cache_hit_1:
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 
    nop ax 

    dec edi
    jnz test_uop_cache_hit
    ret

我们有以下情节:

enter image description here

uop图又是合理的。从icache_64b.iftag_hit中得出的结论是,预测要采取的分支会引起li1标签查找,以便在uop缓存中找到相应的条目(即使分支源和目标属于同一行)。有了这个观察,Intel Optimization Manual/2.5.5.2

一旦从旧版管道中交付了微型操作程序,解码的ICache中的微操作只能在下一次之后恢复分支微操作。

对我来说看起来很合理。

现在考虑一点点有趣

示例3。

我将使用汇编程序伪代码来节省空间

align 64
test_uop_cache_hit:
     8 * nop ax

    19 * nop
    jmp test_uop_cache_hit_1  
align 32:
test_uop_cache_hit_1: ;new line starts here
;more 8 * nop ax 19 * nop jmp blocks
    dec edi
    jnz test_uop_cache_hit
    ret 

我们得到以下结果

enter image description hereenter image description here

这里有趣的是,即使插入了已插入的分支微操作,并且8 * nop ax仍完全适合uop缓存它们没有从uop缓存中传递。从图上可以看到从uop缓存传递的唯一微操作是宏融合dec-jnz

结果让我觉得,如果某些32字节区域不适合uop缓存,则整个缓存行都标记为不包含在uop缓存中,下次要求它的任何32字节部分将被传递来自旧版解码管道。

要从旧版解码管道切换,是否需要分支微型操作?要检查它,请考虑

示例4。

align 32
test_uop_cache_hit:
    32 * nop
test_uop_cache_hit_0: ;new line start here
    16 * nop ax
    ;more 16 * nop ax
    dec edi          ;new line start here
    jnz test_uop_cache_hit
    ret

这是dsb的结果

enter image description here

很明显,所有的uops都是从旧的解码管道中传递的。


考虑一些更复杂的示例,以检查在Example 3.下进行的假设是否在此处起作用:

I。

align 32
test_uop_cache_hit:
    6 * nop ax
    test edi, 0x1
    ;ends 64 byte region, misses due to erratum
    ;does not matter for the example
    jnz test_uop_cache_hit_1

    32 * nop
test_uop_cache_hit_1:
    dec edi
    jnz test_uop_cache_hit
    ret

结果是

 1 075 981 881       idq.dsb_uops
50 341 922 587       idq.mite_uops

结果是完全合理的。当不采用分支并传递了32 * nop时,很明显它们无法容纳uop缓存。在32 * nop之后,从旧版解码管道传送融合了dec-jnz的宏。它适合uop缓存,因此,下次采用该分支时,它将从dsb传递。

结果非常接近预期:(1 << 31)/2 = 1073741824

II。

比以前更复杂的示例

align 32
test_uop_cache_hit:
    test edi, 0x1
    jnz test_uop_cache_hit_2
    jmp test_uop_cache_hit_1

;starts new cache line
align 32
test_uop_cache_hit_1:
    8 * nop ax
; 32 byte aligned
test_uop_cache_hit_2:
    6 * nop ax
    nop dword [eax + 1 * eax + 0x1]
    ;End of 32 bytes region
    ;misses due to erratum
    ;Important here
    jmp test_uop_cache_hit_3
test_uop_cache_hit_3:
    dec edi
    jnz test_uop_cache_hit
    ret

这里是结果:

 5 385 033 285      idq.dsb_uops
25 815 684 426      idq.mite_uops

预期结果。每次获取dec edi - jnz test_uop_cache_hit_2时,它都会跳转到末尾包含jmp的32字节区域。因此它将错过dsb。下次不获取dec edi - jnz test_uop_cache_hit_2时,获取jmp test_uop_cache_hit_1。通常,由于8 * nop ax非常适合dsb,因此它会命中dsb,但请记住,在上一个循环迭代中,在32字节区域末尾的jmp会导致丢失。它们都属于同一高速缓存行,因此,每次迭代都会发生dsb丢失。

结果几乎接近预期:(1 << 31) + (1 << 31)/2 + (1 << 31) = 5368709120

从32字节区域中只删除一个nop ax,并以jmp结尾,同时保留test_uop_cache_hit_3 32字节对齐会导致所有uops从dsb传递:

29 081 868 658       idq.dsb_uops
     8 887 726      idq.mite_uops

注:如果预测每个高速缓存行有2个分支,结果将是非常不可预测的,因此很难给出合理的估计。我不清楚为什么。

© www.soinside.com 2019 - 2024. All rights reserved.