質問

私は非常に重要なカップルの行で私のコードを何らかの改善を得る方法を見つけようとしてきました:

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

すべてa、b、c ...はフロートです。

私は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 ++コードよりも遅い理由を理解する必要がありますか?

Visual Studio 2005、Windows XPでコンパイルして、ASSITに追加情報を提供する場合は、HTを使用してPentium 4を使用しています。

前もって感謝します!

役に立ちましたか?

解決

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

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

SSEを最大限に活用するには、アルゴリズム全体とアルゴリズムが使用するデータを見る必要があります。 A、B、C、およびE、F、G、およびHの値は、SSEレジスタをロードする前にメモリ内にシフトデータがないように、それらの配列で永続的に必要です。簡単ではなく、コードとデータの多くの再加工が必要になる場合があります(ディスクにデータを別の方法で保存する必要がある場合があります)。

また、SSEは32ビット(またはダブルを使用する場合は64ビット)であることを指摘する価値があるかもしれませんが、FPUは80ビット(フロートまたはダブルに関係なく)であるため、FPUを使用するのと比較してSSEを使用するとわずかに異なる結果が得られます。これが問題になるかどうかを知っているのはあなただけです。

他のヒント

あなたは非常に遅い、整理されていない命令を使用しています。データ、16バイトの境界、およびMOVAPSを使用して、データを正しく調整してみてください。より良い代替手段は、アセンブリではなく内insicsを使用することです。なぜなら、コンパイラは必要と思われる指示を自由に注文できるからです。

新しいバージョンと2005年のプログラムオプションでSSEとSSE2の使用を有効にすることができます。Expressバージョンを使用してコンパイルしますか?

また、シリアルC ++をコンパイルすると、コンパイラがスマートであり、非常に迅速にすることで非常に良い仕事をするため、SSEのコードはおそらく遅くなります。操作がシリアルで発生した場合、コンパイラは、たとえばキャッシュとページングの影響を減らすことができます。ただし、インラインアセンブラーはせいぜい不十分に最適化でき、可能な限り避ける必要があります。

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

これは古いスレッドですが、私はあなたの例で間違いに気づきました。これを実行したい場合:

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に動作させるために、多くの時間が失われているため、SSEにうまく変換されません。

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

まず、128bit(16Byte)を調整したものがある場合は、Movapsをはるかに高速にすることができるため、Movapsを使用する必要があります。コンパイラは通常、32ビットシステムであっても、16Byteアラインメントを提供する必要があります。

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

1つのXMMレジスタの4つのフロートには、他のレジスタの4つのフロートが掛けられます。あなたに与える:

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

SSE1では、shufpsを使用して、乗算する前に両方のレジスタでフロートを並べ替える必要があります。

また、CPUキャッシュよりも大きいデータの処理については、非同時のストア(MOVNTPS)を使用してキャッシュ汚染を減らすことができます。他のケースでは、非同時期の店舗は非常に遅いことに注意してください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top