我使用以下方法在SSE和AVX中编写矩阵向量乘法:
for(size_t i=0;i<M;i++) { size_t index = i*N; __m128 a,x,r1; __m128 sum = _mm_setzero_ps(); for(size_t j=0;j<N;j+=4,index+=4) { a = _mm_load_ps(&A[index]); x = _mm_load_ps(&X[j]); r1 = _mm_mul_ps(a,x); sum = _mm_add_ps(r1,sum); } sum = _mm_hadd_ps(sum,sum); sum = _mm_hadd_ps(sum,sum); _mm_store_ss(&C[i],sum); }
我对AVX使用了类似的方法,但最后,由于AVX没有与_mm_store_ss()的等效指令,我使用了:
_mm_store_ss(&C[i],_mm256_castps256_ps128(sum));
SSE代码比串行代码的速度提高了3.7.但是,AVX代码比串行代码的速度提高了4.3.
我知道将SSE与AVX一起使用可能会导致问题,但是我用-mavx’标志使用g编译它应该删除SSE操作码.
我也可以使用:_mm256_storeu_ps(& C [i],sum)做同样的事情,但加速是一样的.
关于我可以做些什么来提高性能的任何见解?它可以与:performance_memory_bound相关,虽然我不明白该线程的答案.
此外,即使包含“immintrin.h”头文件,我也无法使用_mm_fmadd_ps()指令.我启用了FMA和AVX.
解决方法
我建议你重新考虑你的算法.参见讨论
Efficient 4×4 matrix vector multiplication with SSE: horizontal add and dot product – what’s the point?
你正在做一个长点产品并且每次迭代使用_mm_hadd_ps.相反,你应该使用SSE一起做四个点产品(8个用AVX)并且只使用垂直操作符.
您需要添加,乘法和广播.这可以通过_mm_add_ps,_mm_mul_ps和_mm_shuffle_ps(用于广播)在SSE中完成.
如果你已经有了矩阵的转置,这非常简单.
但无论你是否有转置,你都需要让代码更加缓存友好.为了解决这个问题,我建议对矩阵进行循环平铺.请参阅此讨论What is the fastest way to transpose a matrix in C++?,以了解如何进行循环平铺.
在尝试SSE / AVX之前,我会尝试先将循环平铺放到第一位.我在矩阵乘法中获得的最大提升不是来自SIMD,也不是来自循环平铺的线程.我认为如果你获得了缓存使用权,你的AVX代码也会比SSE更加线性.