我有以下matlab代码:
randarray = gpuArray(rand(N,1));
N = 1000;
tic
g=0;
for i=1:N
if randarray(i)>10
g=g+1;
end
end
toc
secondrandarray = rand(N,1);
g=0;
tic
for i=1:N
if secondrandarray(i)>10
g=g+1;
end
end
toc
Elapsed time is 0.221710 seconds.
Elapsed time is 0.000012 seconds.
1)为什么GPU上的if子句这么慢?它减缓了我在优化方面的所有尝试
2)我可以做些什么来解决这个限制?
由于
答案 0 :(得分:6)
无论你是在cpu还是在gpu上做这件事,这通常是件坏事。
以下是您正在进行的操作的好方法。
N = 1000;
randarray = gpuArray(100 * rand(N,1));
tic
g = nnz(randarray > 10);
toc
我没有PCT,我无法验证这是否真的有效(GPU支持的功能数量相当有限)。
但是如果你有Jacket,你肯定能够做到以下几点。
N = 1000;
randarray = gdouble(100 * rand(N, 1));
tic
g = nnz(randarray > 10);
toc
完全披露:我是开发Jacket的工程师之一。
答案 1 :(得分:1)
没有关于Matlab gpuArray
实现的专家,但我怀疑第一个循环中的每个randarray(i)
访问都会触发PCI-e事务以从GPU内存中检索一个值,这将导致非常大延迟惩罚。通过调用gather
在单个事务中传输整个数组,然后循环遍历主机内存中的本地副本,可能会更好地为您服务。
答案 2 :(得分:1)
在现在相当老的GPU(Tesla C1060)上使用MATLAB R2011b和Parallel Computing Toolbox,这就是我所看到的:
>> g = 100*parallel.gpu.GPUArray.rand(1, 1000);
>> tic, sum(g>10); toc
Elapsed time is 0.000474 seconds.
一次对gpuArray
个标量元素进行操作总是很慢,因此使用sum
方法要快得多。
答案 3 :(得分:0)
我无法对先前的解决方案发表评论,因为我太新了,但延伸了Pavan的解决方案。 nxz函数(尚未)为gpuArrays实现,至少在我正在使用的Matlab版本(R2012a)上实现。
通常,矢量化Matlab代码要好得多。但是,在某些情况下,由于JIT编译,循环代码可以在Matlab中快速运行。
检查
的结果N = 1000;
randarray_cpu = rand(N,1);
randarray_gpu = gpuArray(randarray_cpu);
threshold = 0.5;
% CPU: looped
g=0;
tic
for i=1:N
if randarray_cpu(i)>threshold
g=g+1;
end
end
toc
% CPU: vectorized
tic
g = nnz(randarray_cpu>threshold);
toc
% GPU: looped
tic
g=0;
for i=1:N
if randarray_gpu(i)>threshold
g=g+1;
end
end
toc
% GPU: vectorized
tic
g_d = sum(randarray_gpu > threshold);
g = gather(g_d); % I'm assuming that you want this in the CPU at some point
toc
这是(在我的核心i7 + GeForce 560Ti上):
Elapsed time is 0.000014 seconds.
Elapsed time is 0.000580 seconds.
Elapsed time is 0.310218 seconds.
Elapsed time is 0.000558 seconds.
所以我们从这个案例中看到的是:
Matlab中的循环不被视为良好的实践,但在您的特定情况下,它确实运行得很快,因为Matlab以某种方式在内部“预编译”它。我将你的阈值从10改为0.5,因为rand永远不会给你一个高于1的值。
循环GPU版本执行可怕,因为在每次循环迭代时,都会启动内核(或者从GPU读取数据,但是TMW实现了......),这很慢。在计算基本上什么都没有的时候,很多小内存传输都是GPU上最糟糕的事情。
从上一个(最佳)GPU结果来看,答案是:除非数据已经在GPU上,否则在GPU上进行计算是没有意义的。由于操作的算术复杂性基本上不存在,因此内存传输开销不会以任何方式得到回报。如果这是更大的GPU计算的一部分,那就没关系。如果不是......更好地坚持CPU;)