【发布时间】:2013-04-06 00:03:40
【问题描述】:
(正确且有指导意义的回答,见下文)
我开始用 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 化版本的算法会发生什么:
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 卡,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=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。
伟大的比丘! ;)
【问题讨论】:
-
我很确定在 for 循环的执行过程中,某些东西会从设备移动到主机并再次返回。有任何方法可以观察是否(以及何时)传输设备 主机出现??
-
这可能不是最好的方法。整个事情可以向量化为:
pig = nnz(sum(X.^2,2)<=1) * 4 / size(X,1)whereX=rand(N,2)or similar array on the gpu -
跑题了,但这里有一个很好的模拟动画:pastebin.com/w0N46vJE :) 类似于:en.wikipedia.org/wiki/File:Pi_30K.gif
-
欢迎您的链接!