2017-01-25 9 views
4

私は奇妙な出来事があり、それを実際に説明することはできません。私はいくつかの数値コードを書こうとしているので、いくつかの実装をベンチマークしています。私はちょうどSSEAVXとベクトル自動追加といくつかのベクトル追加をベンチマークしたかった。これをテストするために、私は以下のコードを使用して修正しました。AVX、SSEの合計はgccの自動ベクトル化よりも遅い

コード:タイミングや計算GFLOP/Sの場合

#include <iostream> 
#include <immintrin.h> 

#include "../../time/timer.hpp" 


void ser(double* a, double* b, double* res, int size){ 
for(int i(0); i < size; i++) 
{ 
    res[i] = a[i] + b[i]; 
} 
} 

void sse(double* a, double* b, double* res, int size){ 
for (int i(0); i < (size & ~0x1); i += 2) 
{ 
    const __m128d kA2 = _mm_load_pd(&a[i]); 
    const __m128d kB2 = _mm_load_pd(&b[i]); 
    const __m128d kRes = _mm_add_pd(kA2, kB2); 
    _mm_store_pd(&res[i], kRes); 
} 
} 

void avx(double* a, double* b, double* res, int size){ 
for (int i(0); i < (size & ~0x3); i += 4) 
{ 
    const __m256d kA4 = _mm256_load_pd(&a[i]); 
    const __m256d kB4 = _mm256_load_pd(&b[i]); 
    const __m256d kRes = _mm256_add_pd(kA4, kB4); 
    _mm256_store_pd(&res[i], kRes); 
} 
} 


#define N 1e7*64 

int main(int argc, char const *argv[]) 
{ 


double* a = (double*)_mm_malloc(N*sizeof(double), 64); 
double* b = (double*)_mm_malloc(N*sizeof(double), 64); 
double* res = (double*)_mm_malloc(N*sizeof(double), 64); 

Timer tm; 

tm.start(); 
avx(a,b,res,N); 
tm.stop(); 
std::cout<<"AVX\t"<<tm.elapsed()<<" ms\t" 
      <<1e-6*N/tm.elapsed() <<" GFLOP/s"<<std::endl; 

tm.start(); 
sse(a,b,res,N); 
tm.stop(); 
std::cout<<"SSE\t"<<tm.elapsed()<<" ms\t" 
      <<1e-6*N/tm.elapsed() <<" GFLOP/s"<<std::endl; 

tm.start(); 
ser(a,b,res,N); 
tm.stop(); 
std::cout<<"SER\t"<<tm.elapsed()<<" ms\t" 
      <<1e-6*N/tm.elapsed() <<" GFLOP/s"<<std::endl; 
return 0; 
} 

、私が取得:はっきり本当に約170 GFLOP /秒ののpeak performanceに比べて遅い

./test3 
AVX 1892 ms 0.338266 GFLOP/s 
SSE 408 ms 1.56863 GFLOP/s 
SER 396 ms 1.61616 GFLOP/s 

私のi5 6600K。

ここで重要な情報がありません。私は、CPU上でのベクトルの追加は最善の考えではないことを知っていますが、これらの結果は実際には悪いことです。どんな手がかりもありがとう。

+8

あなたは非常に一般的な(ただし明白ではない)ベンチマークミスをしました。あなたは 'malloc()'からメモリを初期化するのを忘れていました。 AVXテスト(最初に実行される)は実際にはページ違反です。 – Mysticial

+1

これを修正すると、この問題が発生します。http://stackoverflow.com/questions/18159455/why-vectorizing-the-loop-does-not-have-performance-improvement – Mysticial

+1

@ミスチカルな権利!私は今ホットメモリでベンチマークを行い、すべてのベクトル化でほぼ同じパフォーマンスを得ます!ありがとう。 –

答えて

-2

これは、分岐予測(より詳細な説明については、Why is it faster to process a sorted array than an unsorted array?を読んでください)と関連しています。私のi5-4200Uでは、100000000をAVX、SSE、SERの順に2倍に処理すると、これが表示されます。

AVX 807 ms 0.123916 GFLOP/s SSE 215 ms 0.465116 GFLOP/s SER 287 ms 0.348432 GFLOP/s

しかし、私はSER、AVX、SSEに変更した場合、それはこれまでのところ、私は知らないあなたのCPUのピークパフォーマンスからだなぜ私はこの

SER 753 ms 0.132802 GFLOP/s AVX 225 ms 0.444444 GFLOP/s SSE 196 ms 0.510204 GFLOP/s

を取得します。

+2

これは分岐予測とは関係ありません。それはページコミットについてです。メモリがまだコミットされていないので、最初のテストは遅くなります。そのため、ページフォルトが発生します。 – Mysticial

+0

ああ、申し訳ありません。ありがとう。 – JeppeSRC

+0

これは、なぜコンパイラの作者が平均的な人よりも優れていると思われる場合に、AVXを明示的に使用するように努力するのかという疑問を引き起こしますか?コンパイラが自動ベクトル化できない場合は、必要な場合がありますが、命令自体を何らかの形で書くことは、コンパイラが得るよりも良いコードを取得するという前提がありますが、これは確かに確実ではありません。 – Holmz

0

アプリケーションは、CPUに限定されているのではなく、メモリに基づいている可能性があります。言い換えれば、メモリ帯域幅がボトルネックになり、ベクトル化はここではあまり役に立ちません。

関連する問題