【发布时间】:2021-03-25 14:44:28
【问题描述】:
我有一段代码在竞争激烈的锁下运行,因此它需要尽可能快。代码非常简单 - 它是一组数据的基本乘加,如下所示:
for( int i = 0; i < size; i++ )
{
c[i] += (double)a[i] * (double)b[i];
}
在启用 SSE 支持的 -O3 下,代码正在按照我的预期进行矢量化。但是,启用 AVX 代码生成后,我得到了大约 10-15% 的减速而不是加速,我不知道为什么。
这是基准代码:
#include <chrono>
#include <cstdio>
#include <cstdlib>
int main()
{
int size = 1 << 20;
float *a = new float[size];
float *b = new float[size];
double *c = new double[size];
for (int i = 0; i < size; i++)
{
a[i] = rand();
b[i] = rand();
c[i] = rand();
}
for (int j = 0; j < 10; j++)
{
auto begin = std::chrono::high_resolution_clock::now();
for( int i = 0; i < size; i++ )
{
c[i] += (double)a[i] * (double)b[i];
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
printf("%lluus\n", duration);
}
}
这是在 SSE 下生成的程序集:
0x100007340 <+144>: cvtps2pd (%r13,%rbx,4), %xmm0
0x100007346 <+150>: cvtps2pd 0x8(%r13,%rbx,4), %xmm1
0x10000734c <+156>: cvtps2pd (%r15,%rbx,4), %xmm2
0x100007351 <+161>: mulpd %xmm0, %xmm2
0x100007355 <+165>: cvtps2pd 0x8(%r15,%rbx,4), %xmm0
0x10000735b <+171>: mulpd %xmm1, %xmm0
0x10000735f <+175>: movupd (%r14,%rbx,8), %xmm1
0x100007365 <+181>: addpd %xmm2, %xmm1
0x100007369 <+185>: movupd 0x10(%r14,%rbx,8), %xmm2
0x100007370 <+192>: addpd %xmm0, %xmm2
0x100007374 <+196>: movupd %xmm1, (%r14,%rbx,8)
0x10000737a <+202>: movupd %xmm2, 0x10(%r14,%rbx,8)
0x100007381 <+209>: addq $0x4, %rbx
0x100007385 <+213>: cmpq $0x100000, %rbx ; imm = 0x100000
0x10000738c <+220>: jne 0x100007340 ; <+144> at main.cpp:26:20
运行 SSE 基准测试的结果:
1411us
1246us
1243us
1267us
1242us
1237us
1246us
1242us
1250us
1229us
启用 AVX 的生成程序集:
0x1000070b0 <+144>: vcvtps2pd (%r13,%rbx,4), %ymm0
0x1000070b7 <+151>: vcvtps2pd 0x10(%r13,%rbx,4), %ymm1
0x1000070be <+158>: vcvtps2pd 0x20(%r13,%rbx,4), %ymm2
0x1000070c5 <+165>: vcvtps2pd 0x30(%r13,%rbx,4), %ymm3
0x1000070cc <+172>: vcvtps2pd (%r15,%rbx,4), %ymm4
0x1000070d2 <+178>: vmulpd %ymm4, %ymm0, %ymm0
0x1000070d6 <+182>: vcvtps2pd 0x10(%r15,%rbx,4), %ymm4
0x1000070dd <+189>: vmulpd %ymm4, %ymm1, %ymm1
0x1000070e1 <+193>: vcvtps2pd 0x20(%r15,%rbx,4), %ymm4
0x1000070e8 <+200>: vcvtps2pd 0x30(%r15,%rbx,4), %ymm5
0x1000070ef <+207>: vmulpd %ymm4, %ymm2, %ymm2
0x1000070f3 <+211>: vmulpd %ymm5, %ymm3, %ymm3
0x1000070f7 <+215>: vaddpd (%r14,%rbx,8), %ymm0, %ymm0
0x1000070fd <+221>: vaddpd 0x20(%r14,%rbx,8), %ymm1, %ymm1
0x100007104 <+228>: vaddpd 0x40(%r14,%rbx,8), %ymm2, %ymm2
0x10000710b <+235>: vaddpd 0x60(%r14,%rbx,8), %ymm3, %ymm3
0x100007112 <+242>: vmovupd %ymm0, (%r14,%rbx,8)
0x100007118 <+248>: vmovupd %ymm1, 0x20(%r14,%rbx,8)
0x10000711f <+255>: vmovupd %ymm2, 0x40(%r14,%rbx,8)
0x100007126 <+262>: vmovupd %ymm3, 0x60(%r14,%rbx,8)
0x10000712d <+269>: addq $0x10, %rbx
0x100007131 <+273>: cmpq $0x100000, %rbx ; imm = 0x100000
0x100007138 <+280>: jne 0x1000070b0 ; <+144> at main.cpp:26:20
运行 AVX 基准测试的结果:
1532us
1404us
1480us
1464us
1410us
1383us
1333us
1362us
1494us
1526us
请注意,使用两倍于 SSE 的指令生成的 AVX 代码并不重要 - 我尝试手动展开较小的展开(以匹配 SSE),但 AVX 仍然较慢。
就上下文而言,我使用的是 macOS 11 和 Xcode 12,以及带有 Intel Xeon CPU E5-1650 v2 @ 3.50GHz 的 Mac Pro 6.1(垃圾箱)。
【问题讨论】:
-
性能说什么?
-
我没有使用 perf,因为我没有使用 Linux。
标签: c++ performance optimization sse avx