私はベクトルのすべての要素を追加するためのインライン関数を実装しましたが、非SIMD以外のものより高速ではありません。なぜ私のAVX2水平加算機能は非SIMD加算より高速ではありませんか?
宣言:これらは、ベクター内のすべてのint型の値を追加するための私の2つの方法があり
#define N 128
#define M N
int __attribute__((aligned(32)))temp8[8];
__m256i vec;
int __attribute__((aligned(32))) c_result[N][M];
:
まず、非SIMDバージョンは次のとおりです。
_mm256_store_si256((__m256i *)&temp8[0] , vec);
c_result[i][j]= temp8[0]+temp8[1]+temp8[2]+temp8[3]+temp8[4]+temp8[5]+temp8[6]+temp8[7];
第二に、AVX2版:
c_result[i][j] =_mm256_hadd2_epi32(vec);
私は、このようにhadd2を実装:
// my horizontal addition of epi32
inline int _mm256_hadd2_epi32(__m256i a)
{
__m256i a_hi;
a_hi = _mm256_permute2x128_si256(a, a, 1); //maybe 1 should be 4
a = _mm256_hadd_epi32(a, a_hi);
a = _mm256_hadd_epi32(a, a);
a = _mm256_hadd_epi32(a, a);
return _mm256_extract_epi32(a,0);
}
私はgcc
、Linux-mint
、skylake
マイクロアーキテクチャを使用します。
私はそれは以下の理由であるかもしれない推測: 特に要素の順序を変更するには、少なくとも1つのサイクルを必要とする順列に制限ベクトル実行ユニットとは対照的にしっかりとそれらを追加しますSkylakeマイクロアーキテクチャのマイクロアーキテクチャの整数値の4 ALU
があります。次にhadd
命令が続きます。問題は、私は何かが欠けているか、すべての要素を追加するためにSIMDを使う必要はないということですか?
更新日: MULプログラムをリポジトリhereに追加しました。行列の乗算のコード全体にアクセスできました。私が非SIMDバージョンを使用する場合、経過時間は201nsになり、SIMDバージョンでは210nsがかかります。
一歩を踏み出して、このような水平操作を行う必要がある理由を質問してください。本当にパフォーマンス重大なボトルネックの一部になっているのであれば、通常は、ループの後に水平操作を行うだけで済みます。削減の最終ステップとして、通常は重要な部分ではありませんが、パフォーマンスに賢明です。 –
@PaulR、そうです。このようにボトルネックセクションではありません。そして、私は、非SIMDとAVX2バージョンのパフォーマンスを自分自身でテストしたいと思っていました。もちろん、これは研究目的と教育目的です。しかし、その答えが私を助けます。ボトルネックセクションで3,5,7および9の隣接要素を水平方向に追加する必要があるConvolution Matrix Kernelを実装したためです。 – Martin
最適化はそれより少し複雑です。 Agner Fogマニュアルへのリンクについては、x86タグwikiを参照してください。フロントエンド、生成されたuops、ポート、遅延、スループット、依存関係を考慮する必要があります。あなたは* perf *でコードをプロファイリングしましたか? –