トリプルループが自動ベクトル化されるとは思いません。IMOの問題は次のとおりです。
- メモリは、オブジェクトタイプstd::vectorを介してアクセスされます。AFAIKアクセス演算子[]または()がインライン化されていない限り、どのコンパイラもstd :: vectorコードを自動ベクトル化するとは思いませんが、それでも、自動ベクトル化されるかどうかはわかりません。
- コードはメモリエイリアシングに悩まされています。つまり、コンパイラは、参照しているメモリが
img
別のメモリポインタからアクセスされているかどうかを認識していないため、ベクトル化がブロックされる可能性があります。基本的に、プレーンなdouble配列を定義し、他のポインターが同じ場所を参照していないことをコンパイラーに示唆する必要があります。を使用してそれを行うことができると思います__restrict
。 __restrict
このポインタがそのメモリ位置を指す唯一のポインタであり、他のポインタがないため、副作用のリスクがないことをコンパイラに通知します。
デフォルトではメモリは整列されておらず、コンパイラが自動ベクトル化を管理している場合でも、整列されていないメモリのベクトル化は整列されたメモリのベクトル化よりもはるかに遅くなります。自動ベクトル化を活用するためにメモリが32メモリビットアドレスにアラインされ、SSEを最大に活用するためにAVXが16ビットアドレスにアラインされていること、つまり常に32メモリビットアドレスにアラインされていることを確認する必要があります。これは、次の方法で動的に実行できます。
double* buffer = NULL;
posix_memalign((void**) &buffer, 32, size*sizeof(double));
...
free(buffer);
MSVCではこれを行うことができ__declspec(align(32)) double array[size]
ますが、使用している特定のコンパイラをチェックして、正しいアライメントディレクティブを使用していることを確認する必要があります。
もう1つの重要なことは、GNUコンパイラを使用する場合は、フラグ-ftree-vectorizer-verbose=6
を使用して、ループが自動ベクトル化されているかどうかを確認することです。インテル®コンパイラーを使用する場合は、を使用してください-vec-report5
。冗長性と情報出力にはいくつかのレベルがあります。つまり、6と5の数字なので、コンパイラのドキュメントを確認してください。詳細レベルが高いほど、コード内のすべてのループについてより多くのベクトル化情報が得られますが、コンパイラーはリリースモードでのコンパイルが遅くなります。
一般に、コンパイラーを自動ベクトル化するのは簡単ではないことにいつも驚いています。ループは正規に見えるため、コンパイラーが自動ベクトル化するというのはよくある間違いです。
更新:そしてもう1つ、img
実際にページアラインされていることを確認してくださいposix_memalign((void**) &buffer, sysconf(_SC_PAGESIZE), size*sizeof(double));
(これはAVXとSSEがアラインされていることを意味します)。問題は、大きな画像がある場合、このループは実行中にページを切り替える可能性が高く、これも非常にコストがかかることです。これがいわゆるTLBミスだと思います。