2012-01-29 56 views
3

发言,我有以下的MATLAB代码:MATLAB如果与CUDA

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)为什么if语句在GPU上这么慢?它正在放慢我所有的优化尝试

2)我能做些什么来解决这个限制?

感谢

回答

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 

完全披露:我是开发夹克的工程师之一。

+0

所以我应该避免如果/然后像使用CUDA时的魔鬼? – 2012-01-29 18:12:36

+0

RRs_Ghost,这将是一个好主意。当你使用if/while和其他命令时,它会将mem拷贝回主机。在for循环中一堆小(1个元素)mem副本是一个坏主意。 – 2012-01-29 18:23:51

+0

@Pavan:我不相信PCT中的当前gpuArray实现支持nnz。 – talonmies 2012-01-29 19:08:59

1

Matlab的gpuArray实施专家,但我怀疑的是,在第一循环的每个randarray(i)访问触发PCI-E事务中获取从GPU内存的值,这将招致非常大的延迟罚款。通过调用gather可以更好地服务于在单个事务中传输整个阵列,然后循环遍历主机内存中的本地副本。

1

上现在比较旧的GPU(特斯拉C1060)使用MATLAB R2011b和并行计算工具箱,这是我看到:

>> g = 100*parallel.gpu.GPUArray.rand(1, 1000); 
>> tic, sum(g>10); toc 
Elapsed time is 0.000474 seconds. 

操作上gpuArray一次一个标量元素总是将是速度慢,因此使用sum方法要快得多。

0

我不能评论以前的解决方案,因为我太新了,但延伸了Pavan的解决方案。至少在我使用的Matlab版本(R2012a)中,nnz函数(尚未)针对gpuArrays实施。

一般来说,矢量化Matlab代码要好得多。但是,在一些情况下,循环代码可以在Matlab中快速运行,因为JIT编译。

检查从

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,因为兰特永远不会给你一个高于1的值。

循环的GPU版本表现糟糕,因为在每次循环迭代时,启动内核(或从GPU中读取数据,但是TMW实现了......),这是很慢的。在计算基本上没有什么的时候,很多小内存传输是人们可以在GPU上做的最糟糕的事情。

从最后一个(最佳)GPU结果来看,答案是:除非数据已经在GPU上,否则在GPU上计算这些数据是没有意义的。由于您的操作的算术复杂性基本上不存在,因此内存传输开销无法以任何方式回报。如果这是更大的GPU计算的一部分,那就没问题。如果没有...更好地坚持CPU;)