2

タイプの配列が2つありdouble、実行したいvecA += vecB。これまでのところ、私はやってvecA = vecA + vecBおり、私が知る限り、たとえば整数の書き込みi = i + 5は。よりも遅いですi += 5。ですから、__m128dで実行するSSE関数があるかどうか疑問に思っていoperator+=ます。検索しても何も見つかりませんでした。私のアプリケーションはこの操作に約60%の時間を費やしてvecA = vecA + vecBいるため、パフォーマンスの向上が見られます。

以下のコードスニペットのすべての配列は16バイトに整列されており、len常に偶数です。

元のコードは単純です

inline void addToDoubleVectorSSE(
         const double * what, const double * toWhat, double * dest, const unsigned int len)
{
   __m128d * _what      = (__m128d*)what;
   __m128d * _toWhat    = (__m128d*)toWhat;

   for ( register unsigned int i = 0; i < len; i+= 2 )
   {
       *_toWhat = _mm_add_pd( *_what, *_toWhat );
       _what++;
       _toWhat++;
   }
}

http://fastcpp.blogspot.cz/2011/04/how-to-process-stl-vector-using-sse.htmlを読んだ後、著者が今読んだものにすぐに書き込まないことでパフォーマンスが向上するので、試してみました

__m128d * _what         = (__m128d*)what;
__m128d * _toWhat       = (__m128d*)toWhat;
__m128d * _toWhatBase   = (__m128d*)toWhat;

__m128d _dest1;
__m128d _dest2;

for ( register unsigned int i = 0; i < len; i+= 4 )
{
    _toWhatBase = _toWhat;
    _dest1      = _mm_add_pd( *_what++, *_toWhat++ );
    _dest2      = _mm_add_pd( *_what++, *_toWhat++ );

    *_toWhatBase++ = _dest1;
    *_toWhatBase++ = _dest2;
}

しかし、スピード的には改善は起こりません。それで、何かありますoperator+=__m128d?または、doubleの配列に対してoperator + =を実行するために使用できる他の方法はありますか?ターゲットプラットフォームは、MSVCを使用して、常にIntel i7 CPU上のWindows(XPおよび7)になります。

4

2 に答える 2

4

あなたは不必要な仕事をしています、現代のコンパイラはこの種のコードを自動的に生成します。この機能は「自動ベクトル化」と呼ばれます。MSVCはVS2012でもそれをサポートしています。私はあなたのコードをあまり理解できなかったので、次のように書き直しました:

inline void addToDoubleVectorSSE(
         const double * what, double * toWhat, const unsigned int len)
{
    for (unsigned ix = 0; ix < len; ++ix) 
        toWhat[ix] += what[ix];
}

このマシンコードを生成したのは次のとおりです。

00A3102E  xor         eax,eax  
00A31030  movupd      xmm0,xmmword ptr [esp+eax+358h]  
00A31039  movupd      xmm1,xmmword ptr [esp+eax+38h]  
00A3103F  add         eax,10h  
00A31042  addpd       xmm1,xmm0                          // <=== Look!!
00A31046  movupd      xmmword ptr [esp+eax+348h],xmm1  
00A3104F  cmp         eax,320h  
00A31054  jb          wmain+30h (0A31030h) 

コードがどれだけきれいに見えるかを考えると、明らかにこのソリューションを好むべきです。必要に応じてVSバージョンを更新してください。

于 2013-02-27T23:00:49.210 に答える
3

私の知る限り、+=SSE算術演算は一般にレジスタ間またはメモリ間であるが、レジスタ間ではないため、に相当するものはありません。

ただし、リンクしたブログ投稿からのアドバイスを使用して、パフォーマンスを向上させることができます。++トリックがうまくいかなかった理由は、2つの命令間の依存関係を排除しなかったためです。つまり、増分の副作用と_what++_toWhat++2番目の操作のペアが同時に開始されないようにします。改善するには、ループを次のように変更します。

for ( register unsigned int i = 0; i < len; i+= 4, _what += 2, _toWhat += 2, _toWhatBase+=2 )
{
    _toWhatBase = _toWhat;
    _dest1      = _mm_add_pd( *_what, *_toWhat );
    _dest2      = _mm_add_pd( *(_what+1), *(_toWhat+1));

    *_toWhatBase = _dest1;
    *(_toWhatBase+1) = _dest2;
}

変更後、の操作は上の操作から_dest2独立します_dest1

私の壁掛け時計の見積もりによると、この簡単な変更の後、約28%の改善が見られました。

于 2013-02-27T22:44:22.813 に答える