提问人:Matt 提问时间:6/19/2022 最后编辑:Matt 更新时间:6/19/2022 访问量:197
在循环迭代之间使用整个缓存行有什么特别的好处吗?
Is there a special benefit to consuming whole cache lines between iterations of a loop?
问:
我的程序添加了浮点数组,并且在使用 MSVC 和 G++ 进行最大优化编译时展开了 4 倍。我不明白为什么两个编译器都选择展开 4x,所以我做了一些测试,发现只有偶尔在运行时进行 t 检验,用于手动展开 1 对 2 或 1 对 4 迭代,p 值 ~0.03,2-vs-4 很少< 0.05,2-vs-8+ 总是> 0.05。
如果我将编译器设置为使用 128 位向量或 256 位向量,它总是展开 4 倍,这是 64 字节缓存行的倍数(重要还是巧合?
我之所以考虑缓存行,是因为我没想到展开会对按顺序读取和写入千兆字节浮点数的内存绑定程序产生任何影响。在这种情况下,展开应该有好处吗?也有可能没有显着差异,我的样本量不够大。
我发现这篇博客说,对于中等大小的阵列,手动展开阵列副本的速度更快,而对于较长的阵列,流式处理速度更快。它们的 AvxAsyncPFCopier 和 AvxAsyncPFUnrollCopier 函数似乎受益于使用整个缓存行以及手动展开。在博客中进行基准测试,源代码在这里。
#include <iostream>
#include <immintrin.h>
int main() {
// example of manually unrolling float arrays
size_t bytes = sizeof(__m256) * 10;
size_t alignment = sizeof(__m256);
// 10 x 32-byte vectors
__m256* a = (__m256*) _mm_malloc(bytes, alignment);
__m256* b = (__m256*) _mm_malloc(bytes, alignment);
__m256* c = (__m256*) _mm_malloc(bytes, alignment);
for (int i = 0; i < 10; i += 2) {
// cache miss?
// load 2 x 64-byte cache lines:
// 2 x 32-byte vectors from b
// 2 x 32-byte vectors from c
a[i + 0] = _mm256_add_ps(b[i + 0], c[i + 0]);
// cache hit?
a[i + 1] = _mm256_add_ps(b[i + 1], c[i + 1]);
// special bonus for consuming whole cache lines?
}
}
3 个唯一浮点数组的原始源
for (int64_t i = 0; i < size; ++i) {
a[i] = b[i] + c[i];
}
带有 AVX2 指令的 MSVC
a[i] = b[i] + c[i];
00007FF7E2522370 vmovups ymm2,ymmword ptr [rax+rcx]
00007FF7E2522375 vmovups ymm1,ymmword ptr [rcx+rax-20h]
00007FF7E252237B vaddps ymm1,ymm1,ymmword ptr [rax-20h]
00007FF7E2522380 vmovups ymmword ptr [rdx+rax-20h],ymm1
00007FF7E2522386 vaddps ymm1,ymm2,ymmword ptr [rax]
00007FF7E252238A vmovups ymm2,ymmword ptr [rcx+rax+20h]
00007FF7E2522390 vmovups ymmword ptr [rdx+rax],ymm1
00007FF7E2522395 vaddps ymm1,ymm2,ymmword ptr [rax+20h]
00007FF7E252239A vmovups ymm2,ymmword ptr [rcx+rax+40h]
00007FF7E25223A0 vmovups ymmword ptr [rdx+rax+20h],ymm1
00007FF7E25223A6 vaddps ymm1,ymm2,ymmword ptr [rax+40h]
00007FF7E25223AB add r9,20h
00007FF7E25223AF vmovups ymmword ptr [rdx+rax+40h],ymm1
00007FF7E25223B5 lea rax,[rax+80h]
00007FF7E25223BC cmp r9,r10
00007FF7E25223BF jle main$omp$2+0E0h (07FF7E2522370h)
具有默认指令的 MSVC
a[i] = b[i] + c[i];
00007FF71ECB2372 movups xmm0,xmmword ptr [rax-10h]
00007FF71ECB2376 add r9,10h
00007FF71ECB237A movups xmm1,xmmword ptr [rcx+rax-10h]
00007FF71ECB237F movups xmm2,xmmword ptr [rax+rcx]
00007FF71ECB2383 addps xmm1,xmm0
00007FF71ECB2386 movups xmm0,xmmword ptr [rax]
00007FF71ECB2389 addps xmm2,xmm0
00007FF71ECB238C movups xmm0,xmmword ptr [rax+10h]
00007FF71ECB2390 movups xmmword ptr [rdx+rax-10h],xmm1
00007FF71ECB2395 movups xmm1,xmmword ptr [rcx+rax+10h]
00007FF71ECB239A movups xmmword ptr [rdx+rax],xmm2
00007FF71ECB239E movups xmm2,xmmword ptr [rcx+rax+20h]
00007FF71ECB23A3 addps xmm1,xmm0
00007FF71ECB23A6 movups xmm0,xmmword ptr [rax+20h]
00007FF71ECB23AA addps xmm2,xmm0
00007FF71ECB23AD movups xmmword ptr [rdx+rax+10h],xmm1
00007FF71ECB23B2 movups xmmword ptr [rdx+rax+20h],xmm2
00007FF71ECB23B7 add rax,40h
00007FF71ECB23BB cmp r9,r10
00007FF71ECB23BE jle main$omp$2+0D2h (07FF71ECB2372h)
答: 暂无答案
评论
struct alignas(64) Test { float f[16]; };
_
__m256*
_mm256_loadu_ps