我正在用C编写一个OpenCL基准测试。目前,它测量了一个CL设备和使用C代码的系统处理器的融合乘法累加性能。然后对结果的准确性进行交叉检查。
我编写本机代码是为了利用gcc的自动矢量器,它工作正常。不过,我注意到gcc在“-march=native”标志上有一些奇怪的行为。
这是我的循环:
#define BUFFER_SIZE_SQRT 4096
#define SQUARE(n) (n * n)
#define ROUNDS_PER_ITERATION 48
static float* cpu_result_matrix(const float* a, const float* b, const float* c)
{
float* res = aligned_alloc(16, SQUARE(BUFFER_SIZE_SQRT) * sizeof(float));
const unsigned buff_size = SQUARE(BUFFER_SIZE_SQRT);
const unsigned round_cnt = ROUNDS_PER_ITERATION;
float lres;
for(unsigned i = 0; i < buff_size; i++)
{
lres = 0;
for(unsigned j = 0; j < round_cnt; j++)
{
lres += a[i] * ((b[i] * c[i]) + b[i]);
lres += b[i] * ((c[i] * a[i]) + c[i]);
lres += c[i] * ((a[i] * b[i]) + a[i]);
}
res[i] = lres;
}
return res;
}
当我在Broadwell系统上用“-march=native-ofast”编译时,我得到了很好的矢量化AVX代码。
.L19:
vmovups ymm0, YMMWORD PTR [rcx+rdx]
mov eax, 48
vmovups ymm2, YMMWORD PTR [rdi+rdx]
vaddps ymm1, ymm0, ymm5
vmovups ymm3, YMMWORD PTR [rsi+rdx]
vaddps ymm4, ymm2, ymm5
vmulps ymm1, ymm1, ymm2
vfmadd132ps ymm4, ymm1, ymm0
vaddps ymm1, ymm3, ymm5
vmulps ymm0, ymm2, ymm0
vmulps ymm0, ymm0, ymm1
vfmadd132ps ymm4, ymm0, ymm3
vmovaps ymm1, ymm4
vxorps xmm0, xmm0, xmm0
.p2align 4,,10
.p2align 3
在piledriver系统上使用相同标志进行编译会发出sse2指令,但不会发出avx指令,即使体系结构支持它。(我将在这里澄清我的标题,说broadwell和piledriver不一样,但它们都支持相似的向量指令集扩展,所以发出的代码应该相似。)
.L19:
mov eax, 48
movups xmm0, XMMWORD PTR [rcx+rdx]
movups xmm2, XMMWORD PTR [r13+0+rdx]
movaps xmm4, xmm0
movaps xmm1, xmm2
movups xmm3, XMMWORD PTR [rsi+rdx]
addps xmm4, xmm5
addps xmm1, xmm5
mulps xmm4, xmm2
mulps xmm1, xmm0
mulps xmm0, xmm2
addps xmm1, xmm4
movaps xmm4, xmm1
mulps xmm4, xmm3
addps xmm3, xmm5
mulps xmm0, xmm3
addps xmm4, xmm0
pxor xmm0, xmm0
movaps xmm1, xmm4
.p2align 4,,10
.p2align 3
我甚至可以用-march=broadwell编译整个项目,并在piledriver系统上运行,它可以工作,性能提高了大约100%。
我使用gcc 5.1.0进行编译,“-ftree vectorizer verbose”似乎不再工作,因此编译器的行为相当不透明。我还没有发现关于这个标志被弃用的任何信息,所以我不确定它为什么不再工作了,我真的想知道gcc在做什么。
整个项目都在这里:https://github.com/jakogut/clperf/tree/v0.1
最佳答案
AVX被禁用,因为整个AMD推土机系列不能有效处理256位AVX指令。在内部,执行单元只有128位宽。因此,256位操作被拆分,因此在128位以上没有任何好处。
更糟糕的是,在piledriver上,256位存储中存在一个bug,它将吞吐量降低到about 1 every 17 cycles。
您的测试用例似乎异常。关键循环中没有256位存储,这就避免了错误。这(理论上)使得sse与avx在piledriver上处于同一水平。
系带断路器来自piledriver支持的fma3指令。这可能就是为什么avx循环在piledriver上变得更快的原因。
你可以试试看会发生什么。