Matlab CUDA基础实验

时间:2013-04-13 14:05:54

标签: matlab cuda

(正确且有指导性地回答,见下文)

我开始用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

这需要很少的时间在CPU上执行,并将100000点“抛入”单位圆圈:

   >> tic; mc1vecnocuda(100000);toc;

      Elapsed time is 0.092473 seconds.

相反,请参阅gpu-ized版本的算法会发生什么:

   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.

我不明白为什么。我使用parfor循环和1024个工作程序,因为使用gpuDevice查询我的nvidia卡,1024是gtx660允许的最大同时线程数。

有人能帮助我吗?感谢。

编辑:这是避免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 = 10百万的执行时间:

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

我没有测试我原来的cuda版本(/ parfor),因为它的执行需要几个小时,n = 10000000。

伟大的比奇伊! ;)

3 个答案:

答案 0 :(得分:3)

我想问题出在parfor

parfor应该在MATLAB工作者上运行,这是你的主机而不是GPU! 我想实际发生的是你在你的主机上启动了1024个线程(而不是你的GPU),并且每个线程都试图调用GPU。这导致您的代码花费了大量时间。

尝试重新编写代码以使用矩阵和数组操作,而不是for-loops!这将显示一些加速。此外,请记住,您应该在GPU中进行更多计算,否则,内存传输将主导您的代码。

代码:

这是包含几个人的所有更正和建议后的最终代码:

function pig = mc2veccuda(n)
  A=gpuArray.rand(n,2); % An nx2 random matrix
  Asq = A.^2; % Get the square value of each element
  Anormsq = Asq(:,1)+Asq(:,2); % Get the norm squared of each point
  gpucountr = nnz(Anorm<1); % Check the number of elements < 1
  pig=(gpucountr/n)*4;

答案 1 :(得分:1)

许多原因如:

  1. 主机与数据之间的数据移动设备
  2. 每个循环内的计算非常小
  3. 在GPU上调用rand可能不是并行
  4. 循环中的
  5. if条件会导致分歧
  6. 对公共变量的累积可以串行运行,但有开销
  7. 很难分析Matlab + CUDA代码。您应该尝试使用本机C ++ / CUDA并使用并行Nsight来找到瓶颈。

答案 2 :(得分:1)

正如Bichoy所说,CUDA代码应该始终进行矢量化。在MATLAB中,除非您正在编写CUDA Kernal,否则您获得的唯一大型加速是在具有数千个(慢)内核的GPU上调用矢量化操作。如果你没有大型矢量和矢量化代码,它就不会有帮助。


还没有提到的另一件事是,对于像GPU这样的高度并行架构,你想使用不同的随机数生成算法而不是&#34;标准&#34;那些。所以要添加Bichoy的答案,添加参数&#39; Threefry4x64&#39; (64位)或&#39; Philox4x32-10&#39; (32位且速度更快!超快!)可以导致CUDA代码的大幅加速。 MATLAB在此解释了这一点:http://www.mathworks.com/help/distcomp/examples/generating-random-numbers-on-a-gpu.html