Go语言SIMD实现性能未达预期,寻求优化指导
Go中float32切片逐元素相乘的性能优化实验与问题
实验环境与场景
- 硬件:3.7GHz AMD 12核处理器(睿频约4.1GHz)
- 场景:两个大型float32切片的逐元素相乘,目标是实现最优性能
基础循环与优化结果
基础单乘法循环
性能:42亿次操作/秒
手动循环展开
手动展开循环的代码如下,但Go编译器默认优化已自动完成循环展开,性能与基础循环一致:
for i := 0; i < len(a); i += 4 { s0 := a[i] * b[i] s1 := a[i+1] * b[i+1] s2 := a[i+2] * b[i+2] s3 := a[i+3] * b[i+3] sum += s0 + s1 + s2 + s3 }
边界检查优化
- 直接禁用编译器边界检查后,性能提升至82亿次操作/秒
- 通过循环内添加切片容量检查让编译器自动消除边界检查,性能为76亿次操作/秒,代码如下:
for i := 0; i < len(a) && i < len(b); i += 4 { aTmp := a[i : i+4 : i+4] bTmp := b[i : i+4 : i+4] s0 := aTmp[0] * bTmp[0] s1 := aTmp[1] * bTmp[1] s2 := aTmp[2] * bTmp[2] s3 := aTmp[3] * bTmp[3] sum += s0 + s1 + s2 + s3 }
SIMD方案尝试与问题
gensimd库实现
使用github.com/bjwbell/gensimd/simd库实现SIMD乘法,理论上应利用256位寄存器完成4次并行乘法,但实际性能仅为11亿次操作/秒,代码如下:
for i := 0; i < len(a); i += 4 { a := simd.MulF32x4(simd.F32x4{a[i], a[i+1], a[i+2], a[i+3]}, simd.F32x4{b[i], b[i+1], b[i+2], b[i+3]}) sum += a[0] + a[1] + a[2] + a[3] }
CGo+汇编Intrinsics实现
通过CGo结合AVX2 intrinsics实现,每次处理8个float32元素,性能为29亿次操作/秒:
Go侧代码:
C.add_arrays((*C.float)(unsafe.Pointer(&a[0])), (*C.float)(unsafe.Pointer(&b[0])), C.int(len(a)))
C侧代码:
void add_arrays(float* a, float* b, int len) { __m256 va, vb, vsum; for (int i = 0; i < len; i += 8) { va = _mm256_load_ps(a + i); vb = _mm256_load_ps(b + i); vsum = _mm256_mul_ps(va, vb); _mm256_store_ps(a + i, vsum); } }
疑问
预期SIMD实现性能应远超循环展开版本,但实际结果相反,请问是Go实现有误还是遗漏了优化点?希望得到相关建议。
内容的提问来源于stack exchange,提问作者spotnag
相关产品推荐
相关产品推荐

