我已经实现了标量矩阵加法内核。
#include <stdio.h>
#include <time.h>
//#include <x86intrin.h>
//loops and iterations:
#define N 128
#define M N
#define NUM_LOOP 1000000
float __attribute__(( aligned(32))) A[N][M],
__attribute__(( aligned(32))) B[N][M],
__attribute__(( aligned(32))) C[N][M];
int main()
{
int w=0, i, j;
struct timespec tStart, tEnd;//used to record the processiing time
double tTotal , tBest=10000;//minimum of toltal time will asign to the best time
do{
clock_gettime(CLOCK_MONOTONIC,&tStart);
for( i=0;i<N;i++){
for(j=0;j<M;j++){
C[i][j]= A[i][j] + B[i][j];
}
}
clock_gettime(CLOCK_MONOTONIC,&tEnd);
tTotal = (tEnd.tv_sec - tStart.tv_sec);
tTotal += (tEnd.tv_nsec - tStart.tv_nsec) / 1000000000.0;
if(tTotal<tBest)
tBest=tTotal;
} while(w++ < NUM_LOOP);
printf(" The best time: %lf sec in %d repetition for %dX%d matrix\n",tBest,w, N, M);
return 0;
}
在这种情况下,我使用不同的编译器标志编译了该程序,内部循环的汇编输出如下所示:
gcc -O2 msse4.2
:128X128矩阵的最佳时间为0.000024秒,在406490次重复中。movss xmm1, DWORD PTR A[rcx+rax]
addss xmm1, DWORD PTR B[rcx+rax]
movss DWORD PTR C[rcx+rax], xmm1
gcc -O2 -mavx
: 在重复执行1000001次128X128矩阵的情况下,最佳时间为0.000009秒。
vmovss xmm1, DWORD PTR A[rcx+rax]
vaddss xmm1, xmm1, DWORD PTR B[rcx+rax]
vmovss DWORD PTR C[rcx+rax], xmm1
AVX版本 gcc -O2 -mavx
:
__m256 vec256;
for(i=0;i<N;i++){
for(j=0;j<M;j+=8){
vec256 = _mm256_add_ps( _mm256_load_ps(&A[i+1][j]) , _mm256_load_ps(&B[i+1][j]));
_mm256_store_ps(&C[i+1][j], vec256);
}
}
SSE版本 gcc -O2 -sse4.2
::
__m128 vec128;
for(i=0;i<N;i++){
for(j=0;j<M;j+=4){
vec128= _mm_add_ps( _mm_load_ps(&A[i][j]) , _mm_load_ps(&B[i][j]));
_mm_store_ps(&C[i][j], vec128);
}
}
在标量程序中,使用
-mavx
比使用 msse4.2
的加速比为 2.7 倍。我知道 avx
提高了 ISA 的效率,可能是因为这些改进。但当我分别使用 AVX
和 SSE
的内部函数实现该程序时,加速比为 3 倍。问题是:在标量模式下,使用 AVX 比 SSE 快 2.7 倍,但矢量化后加速比为 3 倍(此问题的矩阵大小为 128x128)。这有意义吗?尽管在标量模式下使用 AVX 和 SSE 会产生 2.7 倍的加速,但矢量化方法必须更好,因为我在 AVX 中处理八个元素,而在 SSE 中只处理四个元素。所有程序都缺少小于 4.5% 的缓存未命中,如 perf stat
报告的那样。
使用 gcc -O2
,linux mint
,skylake
更新:简言之,标量-AVX 比标量-SSE 快 2.7 倍,但 AVX-256 矢量化后仅比 SSE-128 快 3 倍。我认为这可能是由于流水线的原因。在标量模式下,我有 3 个 vec-ALU
,这在矢量化模式下可能无法使用。我可能比较了苹果和橙子,而不是苹果和苹果,这可能是我无法理解原因的关键。
-ftree-loop-vectorize
启用的,该选项在启用-O3
但未启用-O2
时启用。即使使用-O1 -ftree-loop-vectorize
也会进行向量化。 - Z boson-O3
(我认为没有必要挑剔我的观察中错误的“only”部分)。对于 OP:我也不理解你的意思:“使用 -mavx 比 msse4.2 快 2.7 倍”似乎与“标量-SSE 比标量-AVX 快 2.7 倍”相矛盾,而且你还明确地要求 GCC 生成 VEX 版本(GCC 在使用 -mavx 时抑制 SSEx 指令。当需要时,它会生成新的 AVX 指令或 AVX 等效指令。
),我给了你一个解释这个决策的链接。 - Margaret Bloom-mprefer-avx128
。使用__asm__ __volatile__(“vzeroupper”:::);
的问题在于它会在没有AVX的系统上崩溃。这就是为什么GCC除了asm之外不允许您这样做的原因。如果使用该指令,最好使用-mavx
进行编译。 - Z boson