C++ AMP: Hello GPU

5737 ワード

一部の知識は1つのウェブサイトの説明から抜粋して、自分でプログラムの実現を通じてテストを行って、いくつか感性の認識を得ました
C++AMPは、マイクロソフトが提供するGPUパラレルコンピューティングを利用したAPIです.GPU演算は新しい概念ではなく,GPU演算で有名な既存NVIDIAのCUDA,AMDのstreamである.またOpenCLという規格については皆さんも見たことがないと聞いています(AMPも同様に近日公開規格を出しています).
ガイド:C++AMPはマイクロソフトが提供したGPU並列計算を利用したAPIである.GPU演算は新しい概念ではなく、GPU演算で有名な既存のNVIDIAのCUDA、AMDのstreamである.同时にOpenCLという标准についても皆さんはきっと见たことがないと闻いています(AMPも最近开放标准を出しました).しかし、少なくとも現在は気候のCUDAで、彼はNカードにしか使えない.結局、CUDAはN家の駆動を使うため、Aカードは使えない.ではOpenCLは?多くの大工場にも独自の変種があるので、本格的なコンパイル、プラットフォーム全体の運行はまだ言えません.AMPは優れたプラットフォームの優位性を利用して、もしあなたがwindowsを使うならば、AMPを使うのは2つの選択ではありません.もちろん前提があって、天下は無料の昼食がなくて、あなたのグラフィックカードはDX 11をサポートしなければなりません.
こんなにたくさん言ったので、AMPの様子を見てみましょう.次はHello worldのようなAMPコードの断片です.
ここでGPUプログラミングを実現する:
void MatrixMultiplyGPU(std::vector& vC,
                        const std::vector& vA,
                        const std::vector& vB, int M, int N, int W)

{
    concurrency::array_view a(M, W, vA);
    concurrency::array_view b(W, N, vB);
    concurrency::array_view c(M, N, vC); c.discard_data();

    concurrency::parallel_for_each(c.extent,
        [=](concurrency::index<2> idx) restrict(amp) {
            int row = idx[0]; int col = idx[1];
            float sum = 0.0f;
            for(int i = 0; i < W; i++)
                sum += a(row, i) * b(i, col);
                c[idx] = sum;    
        });
}

もしあなたがすでにvs 11のbetaを装着しているならば、ctrl+c/ctrl+vは急いで体験してみましょう:)はい、このc++が非常に急進的な年代(最近のc++11とこのAMP、研究が好きな子供靴はまた自分の脳細胞を虐待することができます)、上のコードはきっとあなたに多くのぼんやりしているところを持っています.靴を捨てないでね.
比較の核心の場所で、これは私たちのこの行列演算の精髄です.最初の3つのタイプ定義は、私たちはしばらく気にしないで、次に下を見て、parallel_for_each彼は実は関数で、私は最初の目でキーワードforに似ていると思っていました.彼は2つのパラメータを持っていて、1つ目はextentになるもので、現在は理解しやすいように配列の次元として理解することができます.2番目のパラメータはlambdaです.ここはみんな游んでいます.NETの、lambdaに対してきっとよく知らないで、概念の上で多く言う必要はありませんて、主要な点はc++lambdaに対してよく知らないならば、ここを参考にして私达はこのlambdaの中ですべて何をしたことを见ることができますか?[=]lambdaで捕捉変数が伝達値に従って参照されることを示し、restrict(amp)はこのコードがデフォルトデバイス上で実行することを示す.cpuを指定することもできます.(ps.AMP 1 st Releaseにdirect 3 d.)concurrency::index<2>idxというlambdaのパラメータはスレッド単位を表すが、現在lambdaがいくつかのidxを伝えると、いくつかのスレッドがあると考えられる.Lambdaの中の関数については、データを利用して並列に計算し、簡単なマトリクスを乗算することです.
比較のため、CPUプログラミングは同様の機能を実現する:
void MatrixMultiplyCPU(std::vector& vC,
                        const std::vector& vA,
                        const std::vector& vB, int M, int N, int W)
{
    //   GPU         ,       
    concurrency::array_view a(M, W, vA);
    concurrency::array_view b(W, N, vB);
    concurrency::array_view c(M, N, vC); c.discard_data();

    for (int i = 0; i < M; i++)
    {
        for (int j = 0; j < N; j++)
        {
            float sum = 0.0f;
            for (int k = 0; k < W; k++)
            {
                sum += a(i,k) * b(k,j);
            }
            c(i,j) = sum;
        }
    }
}
試験メインプログラムは以下の通りで、実行時間から比較した.
#include 
#include 
#include 

void MatrixMultiplyGPU(std::vector& vC,
                        const std::vector& vA,
                        const std::vector& vB, int M, int N, int W);

void MatrixMultiplyCPU(std::vector& vC,
                        const std::vector& vA,
                        const std::vector& vB, int M, int N, int W);

int main()
{
    int M = 1000, N = 1000, W = 1000;

    std::vector vec_rsltGPU(M * N);
    std::vector vec_rsltCPU(M * N);

    long ACount = M * W;
    std::vector vec_A;
    for (long i = 0; i < ACount; i++ )
    {
        vec_A.push_back((float)rand()/(float)(ACount*ACount));
    }

    int BCount = W * N;
    std::vector vec_B;
    for (long i = 0; i < BCount; i++ )
    {
        vec_B.push_back((float)rand() / (float)(ACount * ACount));
    }

    DWORD  tStart1 = GetTickCount();
    MatrixMultiplyGPU(vec_rsltGPU, vec_A, vec_B, M, N, W);
    DWORD tEnd1 = GetTickCount();

    DWORD  tStart2 = GetTickCount();
    MatrixMultiplyCPU(vec_rsltCPU, vec_A, vec_B, M, N, W);
    DWORD tEnd2 = GetTickCount();

    std::cout << "GPU time:\t" << tEnd1 - tStart1 << std::endl;
    std::cout << "CPU time:\t" << tEnd2 - tStart2 << std::endl;

    system("pause");

    return 0;
}

またline 2を見て、apiを使って、必ずヘッダファイルを含めて、私たちのAMPはとてもみんなのために考えて、こんなに簡単なヘッダファイルだけでいいです.DXの子供靴を使ったことがあってきっとあのincludeの果てしないdxxxxを覚えています.hとdxxxx.lib.
テスト結果:
 
 
M=1000, N=1000, W=1000
M=1000, N=1000, W=100
M=100, N=100, W=1000
M=100, N=100, W=1000
M=100, N=100, W=100
GPU Time
3276
484
500
293
234
CPU Time
358007
42401
38407
4026
452
以上のテストは大体何回か平均として取り、一定の統計的意義を持っている.
CPUの複雑さは処理のデータ規模に直結しており,大規模なデータ処理に対しては並列化処理を効率的に関与させることで演算時間を低減することができる.
朝、会社に行ってDX 11のサポートがないパソコンを試してみましたが、本当に命がけで、直接n個のスレッドを開いて、このような状況になりました.
 
M=100, N=100, W=1000, DX11 Support
M=100, N=100, W=1000,No DX11 Support
GPU Time
293
108888
CPU Time
4026
3167
今回のテストを通して、GPUを用いて並列化計算を行う方法を理解し、次の方法で応用する予定である:ハフ変換による平面パラメータを求めるGPU実現【まだ実現していない】
参照先:http://www.cnblogs.com/baesky
 http://www.infoq.com/cn/articles/cpp_amp_computing_on_GPU 
http://www.parallellabs.com/2012/05/09/cplusplus-amp-programming/ 
http://www.cnblogs.com/yxy8023ustc/archive/2012/12/08/2809389.html