3

C++ AMP の実験を開始しました。何ができるかを確認するためだけに簡単なテスト アプリを作成しましたが、その結果は非常に驚くべきものでした。次のコードを検討してください。

#include <amp.h>
#include "Timer.h"

using namespace concurrency;

int main( int argc, char* argv[] )
{
    uint32_t u32Threads = 16;
    uint32_t u32DataRank = u32Threads * 256;
    uint32_t u32DataSize = (u32DataRank * u32DataRank) / u32Threads;
    uint32_t* pu32Data = new (std::nothrow) uint32_t[ u32DataRank * u32DataRank ];

    for ( uint32_t i = 0; i < u32DataRank * u32DataRank; i++ )
    {
        pu32Data[i] = 1;
    }

    uint32_t* pu32Sum = new (std::nothrow) uint32_t[ u32Threads ];

    Timer tmr;

    tmr.Start();

    array< uint32_t, 1 > source( u32DataRank * u32DataRank, pu32Data ); 
    array_view< uint32_t, 1 > sum( u32Threads, pu32Sum );

    printf( "Array<> deep copy time: %.6f\n", tmr.Stop() );

    tmr.Start();

    parallel_for_each( 
        sum.extent,
        [=, &source](index<1> idx) restrict(amp)
        {
            uint32_t u32Sum = 0;
            uint32_t u32Start = idx[0] * u32DataSize;
            uint32_t u32End = (idx[0] * u32DataSize) + u32DataSize;
            for ( uint32_t i = u32Start; i < u32End; i++ )
            {
                u32Sum += source[i];
            }
            sum[idx] = u32Sum;
        }
    );

    double dDuration = tmr.Stop();
    printf( "gpu computation time: %.6f\n", dDuration );

    tmr.Start();

    sum.synchronize();

    dDuration = tmr.Stop();
    printf( "synchronize time: %.6f\n", dDuration );
    printf( "first and second row sum = %u, %u\n", pu32Sum[0], pu32Sum[1] );

    tmr.Start();

    for ( uint32_t idx = 0; idx < u32Threads; idx++ )
    {
        uint32_t u32Sum = 0;
        for ( uint32_t i = 0; i < u32DataSize; i++ )
        {
            u32Sum += pu32Data[(idx * u32DataSize) + i];
        }
        pu32Sum[idx] = u32Sum;
    }

    dDuration = tmr.Stop();
    printf( "cpu computation time: %.6f\n", dDuration );
    printf( "first and second row sum = %u, %u\n", pu32Sum[0], pu32Sum[1] );

    delete [] pu32Sum;
    delete [] pu32Data;

    return 0;
}

TimerQueryPerformanceCounter を使用した単純なタイミング クラスであることに注意してください。とにかく、コードの出力は次のとおりです。

Array<> deep copy time: 0.089784
gpu computation time: 0.000449
synchronize time: 8.671081
first and second row sum = 1048576, 1048576
cpu computation time: 0.006647
first and second row sum = 1048576, 1048576

synchronize() の呼び出しに時間がかかるのはなぜですか? これを回避する方法はありますか?それ以外の計算性能は素晴らしいのですが、synchronize() のオーバーヘッドがあり、私には使い物になりません。

また、私のやり方が間違っている可能性もありますので、よろしければ教えてください。前もって感謝します。

4

2 に答える 2

5

関数 synchronize() は、実際のカーネルが作業を完了するのを待っているため、おそらく非常に時間がかかっています。

amp.hの parallel_for_each から:

parallel_for_each は呼び出し元のコードと同期しているかのように実行されますが、実際には非同期であることに注意してください。つまり、parallel_for_each 呼び出しが行われ、カーネルがランタイムに渡されると、[parallel_for_each の後のコード] は CPU スレッドによってすぐに実行され続けますが、並行して、カーネルは GPU スレッドによって実行されます。

そのため、parallel_for_each で費やされた時間を測定しても特に意味はありません。

編集: アルゴリズムの記述方法では、GPU アクセラレーションのメリットはあまりありません。source[i] の読み取りは結合されていないため、結合された読み取りよりもほぼ 16 倍遅くなります。共有メモリを使用して読み取りを結合することは可能ですが、簡単ではありません。GPUプログラミングについて読むことをお勧めします。

C++ AMP の有用性を示す簡単な例が必要な場合は、行列の乗算を試してください。

もちろん、観察されるパフォーマンスは、GPU ハードウェアのモデルにも大きく依存します。

于 2012-03-23T22:24:40.237 に答える
3

特定のアルゴリズムに関する Igor の回答に加えて、一般的に C++ AMP のパフォーマンスを測定する方法には複数の誤った側面があることに注意してください (ランタイム初期化の除外なし、初期 JIT の破棄なし、データのウォームアップなし、および既に指摘されているp_f_e が同期的であるという前提がないため)、こちらのガイドラインに従ってください。

http://blogs.msdn.com/b/nativeconcurrency/archive/2011/12/28/how-to-measure-the-performance-of-c-amp-algorithms.aspx

于 2012-03-27T01:48:01.777 に答える