【问题标题】:Intel Core i7 processor and cache behaviourIntel Core i7 处理器和缓存行为
【发布时间】:2017-08-21 19:16:31
【问题描述】:

我在 Intel Core i7 CPU(具有 32KB L1 数据高速缓存和 64B L1 高速缓存行大小)上运行了以下汇编代码:(通过 10 000 000 个元素的数组每个 4 字节迭代 1000 次)

main:
.LFB0:
    .cfi_startproc
    mov edx, 1000
    jmp .L2
.L3:
    mov ecx, DWORD PTR v[0+eax*4]
    add eax, 1

    cmp eax, 10000000
    jl  .L3
    sub edx, 1
    je  .L4
.L2:
    mov eax, 0
    jmp .L3
.L4:
    mov eax, 0
    ret
    .cfi_endproc

Perf 提供以下统计数据:

10,135,716,950      L1-dcache-loads
601,544,266      L1-dcache-load-misses     #    5.93% of all L1-dcache hits
4.747253821 seconds time elapsed

这是完全有道理的,因为我正在访问内存中的 1 000 * 10 000 000 = 10 000 000 000 个元素,并且缓存线为 64B(向量中的元素为 4 B),这意味着每次 L1 缓存未命中16 个元素(因此大约有 625 000 000 次 L1 缓存未命中)。

现在,我已经“展开”了循环的一部分,代码是:

    .cfi_startproc
    mov     edx, 1000
    jmp     .L2
.L3:
    mov     ecx, DWORD PTR v[0+eax*4]
    mov     ecx, DWORD PTR v[0+eax*4 + 4]
    mov     ecx, DWORD PTR v[0+eax*4 + 8]
    mov     ecx, DWORD PTR v[0+eax*4 + 12]

    add     eax, 4

    cmp     eax, 2500000
    jl      .L3
    sub     edx, 1
    je      .L4
.L2:
    mov     eax, 0
    jmp     .L3
.L4:
    mov     eax, 0
    ret
    .cfi_endproc

Perf 如何提供以下统计信息:

2,503,436,639      L1-dcache-loads
123,835,666      L1-dcache-load-misses     #    4.95% of all L1-dcache hits
0.629926637 seconds time elapsed

我不明白为什么?

1) 由于我访问的数据量相同,因此 L1 缓存负载更少?

2) 代码运行速度比第一个版本快 6 倍?我知道它有 与乱序执行和超标量执行有关,但我无法详细解释这一点(我想确切了解导致这种加速的原因)。

【问题讨论】:

    标签: c performance caching assembly intel


    【解决方案1】:

    坏消息 - 你在第二个中有一个错误 ;)

    原始代码

    .L3:
        mov ecx, DWORD PTR v[0+eax*4]
        add eax, 1
        cmp eax, 10000000
        jl  .L3
    

    第二版

    .L3:
        mov     ecx, DWORD PTR v[0+eax*4]
        mov     ecx, DWORD PTR v[0+eax*4 + 4]
        mov     ecx, DWORD PTR v[0+eax*4 + 8]
        mov     ecx, DWORD PTR v[0+eax*4 + 12]
        add     eax, 4
        cmp     eax, 2500000  <- here
        jl      .L3
    

    在这两种情况下,您都需要加载 1000 万个元素。两种情况下访问的最大元素地址必须相同,对吗?

    所以在第一种情况下,最大地址是:

    (10.000.000-1)*4 = 39.999.996
    

    第二个:

    (2.500.000-4)*4+12 = 9.999.996
    

    正好少 4 倍。

    只需将第二个示例也修复为cmp eax, 10000000

    【讨论】:

    • Ok :( 我已经修复了。现在缓存命中和加载都正常。但它仍然执行得更快:2.617806762 秒。为什么?只是因为它必须执行更少的跳转指令?跨度>
    • 展开通常会带来收益。第二件事我们不知道你有哪个 i7。还要检查如果您不总是加载到 ecx 而是加载不同的寄存器会发生什么(前 3 个加载是“无效的”,因为最后一个加载总是覆盖 ecx,因此 CPU 可能会看到这一点并在这里做一些魔术)。还要检查如果展开 8 或 16 次会发生什么。
    猜你喜欢
    • 2010-12-11
    • 2015-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 2010-10-17
    • 1970-01-01
    相关资源
    最近更新 更多