3

(正確かつ有益な回答、以下を参照)

私は、matlab と gpu (nvidia gtx660) で実験を始めています。

ここで、PI を計算するためのこの単純なモンテカルロ アルゴリズムを作成しました。CPU のバージョンは次のとおりです。

function pig = mc1vecnocuda(n)
countr=0;
A=rand(n,2);
 for i=1:n

   if norm(A(i,:))<1
    countr=countr+1;
   end
 end
pig=(countr/n)*4;
end

これは、100000 ポイントが単位円に「投入」された CPU で実行されるのにほとんど時間がかかりません。

   >> tic; mc1vecnocuda(100000);toc;

      Elapsed time is 0.092473 seconds.

代わりに、GPU 化されたバージョンのアルゴリズムで何が起こるかを見てください。

   function pig = mc1veccuda(n)
   countr=0;
   gpucountr=gpuArray(countr);
   A=gpuArray.rand(n,2);
   parfor (i=1:n,1024)
    if norm(A(i,:))<1
        gpucountr=gpucountr+1;
    end
   end

   pig=(gpucountr/n)*4;
   end

さて、これは実行に長い時間がかかります:

>> tic; mc1veccuda(100000);toc;
Elapsed time is 21.137954 seconds.

理由がわかりません。1024 個のワーカーで parfor ループを使用しました。これは、gpuDevice で nvidia カードをクエリすると、gtx660 で許可される同時スレッドの最大数が 1024 になるためです。

誰かが私を助けることができますか?ありがとう。

編集:これはIFを回避する更新版です:

function pig = mc2veccuda(n)
countr=0;
gpucountr=gpuArray(countr);
A=gpuArray.rand(n,2);
parfor (i=1:n,1024)

    gpucountr = gpucountr+nnz(norm(A(i,:))<1);

end

pig=(gpucountr/n)*4;
end

そして、これは Bichoy のガイドラインに従って書かれたコードです (結果を達成するための 正しいコード):

function pig = mc3veccuda(n)
countr=0;
gpucountr=gpuArray(countr);
A=gpuArray.rand(n,2);
Asq = A.^2;
Asqsum_big_column = Asq(:,1)+Asq(:,2);
Anorms=Asqsum_big_column.^(1/2);
gpucountr=gpucountr+nnz(Anorms<1);

pig=(gpucountr/n)*4;
end

n=1000万の実行時間に注意してください:

>> tic; mc3veccuda(10000000); toc;
Elapsed time is 0.131348 seconds.
>> tic; mc1vecnocuda(10000000); toc;
Elapsed time is 8.108907 seconds.

元の cuda バージョン (for/parfor) はテストしませんでした。実行には n=10000000 の場合、数時間かかるからです。

グレートビチョイ!;)

4

3 に答える 3

1

次のような多くの理由:

  1. ホストとデバイス間のデータの移動
  2. 各ループ内の計算は非常に小さい
  3. GPU での呼び出しはrand並列ではない可能性があります
  4. ifループ内の条件により分岐が発生する可能性があります
  5. 共通変数への累積は、オーバーヘッドを伴い、順次実行される場合があります

Matlab+CUDA コードのプロファイリングは困難です。おそらく、ネイティブ C++/CUDA で試し、並列 Nsight を使用してボトルネックを見つける必要があります。

于 2013-04-13T14:28:44.187 に答える
1

Bichoy が言ったように、CUDA コードは常にベクトル化する必要があります。MATLAB では、CUDA カーネルを作成していない限り、得られる唯一の大幅な高速化は、数千の (遅い) コアを持つ GPU でベクトル化された操作が呼び出されることです。大きなベクトルとベクトル化されたコードがない場合、それは役に立ちません。


言及されていないもう1つのことは、GPUのような高度に並列なアーキテクチャでは、「標準」のものとは異なる乱数生成アルゴリズムを使用したいということです. したがって、Bichoy の回答に追加するには、パラメーター 'Threefry4x64' (64 ビット) または 'Philox4x32-10' (32 ビットではるかに高速! 超高速!) を追加すると、CUDA コードの大幅な高速化につながる可能性があります。MATLAB はこれをここで説明します: http://www.mathworks.com/help/distcomp/examples/generating-random-numbers-on-a-gpu.html

于 2016-01-15T17:19:24.297 に答える