這篇文章與我發佈some days ago的另一篇文章密切相關。這一次,我寫了一個簡單的代碼,它只添加一對元素數組,將結果乘以另一個數組中的值,並將其存儲在第四個數組中,所有變量均爲浮點雙精度類型。GCC SSE代碼優化
我做了代碼的兩個版本:一個使用SSE指令,用來調用和另一個沒有他們,我然後用gcc和-O0優化級別編譯它們。我把它們寫在下面:
// SSE VERSION
#define N 10000
#define NTIMES 100000
#include <time.h>
#include <stdio.h>
#include <xmmintrin.h>
#include <pmmintrin.h>
double a[N] __attribute__((aligned(16)));
double b[N] __attribute__((aligned(16)));
double c[N] __attribute__((aligned(16)));
double r[N] __attribute__((aligned(16)));
int main(void){
int i, times;
for(times = 0; times < NTIMES; times++){
for(i = 0; i <N; i+= 2){
__m128d mm_a = _mm_load_pd(&a[i]);
_mm_prefetch(&a[i+4], _MM_HINT_T0);
__m128d mm_b = _mm_load_pd(&b[i]);
_mm_prefetch(&b[i+4] , _MM_HINT_T0);
__m128d mm_c = _mm_load_pd(&c[i]);
_mm_prefetch(&c[i+4] , _MM_HINT_T0);
__m128d mm_r;
mm_r = _mm_add_pd(mm_a, mm_b);
mm_a = _mm_mul_pd(mm_r , mm_c);
_mm_store_pd(&r[i], mm_a);
}
}
}
//NO SSE VERSION
//same definitions as before
int main(void){
int i, times;
for(times = 0; times < NTIMES; times++){
for(i = 0; i < N; i++){
r[i] = (a[i]+b[i])*c[i];
}
}
}
當-O0編譯它們,GCC利用的XMM/MMX寄存器和SSE intstructions,如果沒有具體給出的-mno-SSE(及其他)選項。我檢查了爲第二個代碼生成的彙編代碼,並且我注意到它使用了 movsd, addsd和 mulsd說明。所以它使用SSE指令,但只有那些使用寄存器最低部分的指令,如果我沒有錯的話。用於第一C代碼生成的彙編代碼利用,正如所料, ADDP和 mulpd指令的,儘管產生一個相當大的彙編代碼。
不管怎麼說,第一個代碼應該得到更好的利潤,據我所知,SIMD範式,因爲每次迭代兩個結果值計算。儘管如此,第二個代碼的執行速度比第一個快25%。我還用單精度值進行了測試,得到了類似的結果。這是什麼原因?
沒有優化編譯時對比效果是毫無意義的。 – interjay
您只需進行3次x加載和1次存儲即可進行2次x運算操作,因此您很可能會受到帶寬限制。 –
當您刪除_mm_prefetch調用時會發生什麼?我認爲他們可能會傷害你 – TJD