2

非常に重要な数行でコードを改善する方法を見つけようとしています。

float x = a*b;
float y = c*d;
float z = e*f;
float w = g*h;

a、b、c ... はすべて float です。

SSE の使用を検討することにしましたが、改善が見られないようです。実際には、2 倍遅くなることが判明しました。私のSSEコードは次のとおりです。

Vector4 abcd, efgh, result;
abcd = [float a, float b, float c, float d];
efgh = [float e, float f, float g, float h];
_asm {
movups xmm1, abcd
movups xmm2, efgh
mulps xmm1, xmm2
movups result, xmm1
}

標準のインライン アセンブリも使用してみましたが、SSE のように 4 つの浮動小数点をレジスタにパックできるようには見えません。

コメントやヘルプをいただければ幸いです。主に、SSE を使用した計算がシリアル C++ コードよりも遅い理由を理解する必要がありますか?

Windows XP 上の Visual Studio 2005 で、Pentium 4 と HT を使用してコンパイルしています。

前もって感謝します!

4

5 に答える 5

3

ご存知のように、SSEレジスタを正しくロードするためにメモリ内のデータをシャッフルする必要があり、このデータをメモリ内で移動する必要があるため、いくつかの命令をSSEに置き換えるだけでは機能しません。アレイを構築します)メモリが非常に遅いため、パフォーマンスが低下します(ハードディスクは別として、メモリは常に最近のボトルネックになっています)。

また、RAMへの書き込みとそれに続く読み取りを使用せずにSSEとFPU/ALU間でデータを移動する方法はありません。最新のIA32チップは、この特定のパターン(書き込み、読み取り)にうまく対応しますが、それでも一部のキャッシュを無効にするため、ノックオン効果があります。

SSEを最大限に活用するには、アルゴリズム全体とアルゴリズムが使用するデータを確認する必要があります。SSEレジスタをロードする前にメモリ内でデータがシフトしないように、a、b、c、dおよびe、f、g、hの値はこれらの配列に永続的に存在する必要があります。これは簡単ではなく、コードとデータの多くのやり直しが必要になる場合があります(データをディスクに別の方法で保存する必要がある場合があります)。

また、SSEは32ビット(またはdoubleを使用する場合は64ビット)であるのに対し、FPUは80ビット(floatまたはdoubleに関係なく)であるため、SSEを使用する場合とFPUを使用する場合でわずかに異なる結果が得られることも指摘しておく価値があります。これが問題になるかどうかはあなただけが知っています。

于 2010-06-02T21:33:36.043 に答える
3

非常に遅いアラインされていない命令を使用しています。データを正しく配置し、16 バイト境界で、movaps を使用することをお勧めします。コンパイラは必要に応じて命令を自由に順序付けできるため、アセンブリではなく組み込み関数を使用することをお勧めします。

于 2010-06-02T21:15:46.167 に答える
1

新しい VS バージョンおよびおそらく 2005 では、プログラム オプションで SSE および SSE2 の使用を有効にすることができます。高速バージョンを使用してコンパイルしますか?

また、シリアル C++ をコンパイルする場合、コンパイラはスマートであり、非常に高速にするために非常に優れた仕事をするため、SSE のコードはおそらく遅くなります。たとえば、適切なタイミングで適切なレジスタに自動的に配置されます。操作が連続して行われる場合、コンパイラーは、例えばキャッシュやページングの影響を軽減できます。ただし、インライン アセンブラは最適化が不十分であり、可能な限り避ける必要があります。

さらに、SSE/2 が顕著な利益をもたらすには、膨大な量の作業を実行する必要があります。

于 2010-06-02T21:08:41.630 に答える
1

これは古いスレッドですが、あなたの例に誤りがあることに気付きました。これを実行したい場合:

float x = a*b;
float y = c*d;
float z = e*f;
float w = g*h;

次に、コードは次のようになります。

Vector4 aceg, bdfh, result;  // xyzw
abcd = [float a, float c, float e, float g];
efgh = [float b, float d, float f, float h];
_asm {
movups xmm1, abcd
movups xmm2, efgh
mulps xmm1, xmm2
movups result, xmm1
}

さらに速度を上げるために、「結果」に別のレジスタを使用しないことをお勧めします。

まず第一に、すべてのアルゴリズムが SSE で書き直されるメリットがあるわけではありません。データ駆動型アルゴリズム (ルックアップ テーブル駆動型アルゴリズムなど) は、SSE が動作するためにデータをベクトルにパックおよびアンパックするために多くの時間が失われるため、SSE にうまく変換されません。

これがまだ役立つことを願っています。

于 2012-04-18T18:46:32.743 に答える
0

まず、128 ビット (16 バイト) にアラインされたものがある場合は、はるかに高速になる可能性があるため、MOVAPS を使用する必要があります。コンパイラは通常、32 ビット システムであっても 16 バイト アラインメントを提供するはずです。

C/C++ 行は、sse コードと同じことを行いません。

1 つの xmm レジスターの 4 つの float は、他のレジスターの 4 つの float で乗算されます。あなたに与える:

float x = a*e;
float y = b*f;
float z = c*g;
float w = d*h;

sse1 では、SHUFPS を使用して、乗算する前に両方のレジスタの float を並べ替える必要があります。

また、CPU キャッシュよりも大きいデータを処理する場合は、非テンポラル ストア (MOVNTPS) を使用してキャッシュの汚染を減らすことができます。それ以外の場合、非テンポラル ストアは非常に遅くなることに注意してください。

于 2013-05-18T02:47:55.363 に答える