CUDA:使用嵌套循环并行化具有函数调用的多个嵌套for循环

时间:2018-04-19 22:48:19

标签: loops for-loop parallel-processing cuda

问题

我对使用CUDA并行化问题感兴趣。有问题的C代码遵循以下简化形式:

 int A, B, C; // 100 < A,B,C,D < 1,000

 float* v1, v2, v3;   
 //v1,v2, v3 will have respective size A,B,C
 //and will not be empty

 float*** t1, t2, t3; 
 //t1,t2,t3 will eventually have the size (ci,cj,ck)
 //and will not be empty

 int i, j , k, l;      

 float xi, xj, xk;

 for (i=0; i<A; ++i){   
   xi = ci - v1[i];
   for (j=0; j<B; ++j){
     xj = (j*cj)*cos(j*M_PI/180);   
     for (k=0;k<C; ++k){
       xk = xj - v3[k];
       if (xk < xi){
         call_1(t1[i], v1, t2[i], &t3[i][j][k]);
       }
       else t3[i][j][k] = some_number;
     }   
   } 
 }

此处call_1

void call_1 (float **w, float *x, float **y, float *z){
 int k, max = some_value;
 float *v; //initialize to have size max
 for (k=0; k<max; ++k)
    call_2(x[k], y[k], max, &v[k]);
 call_2(y, v, max, z);
}

此处call_2

void call_2 (float *w, float*x, int y, double *z)

只包含单个while循环内的位移,乘法,减法和加法等操作。

尝试的想法

到目前为止,我的想法是,函数call_1可以转换为内核代码__global__ void call_1;并且call_2可以转换为设备代码而不修改其内容。特别是,我可以让__global__ void call_1成为

double* v; //initialize to have size max

int index = blockIdx.x * blockDim.x + threadIdx.x;
int stride = blockDim.x * gridDim.x;
for (int k=index; k<max; k += stride)
    call_2 (x[k], y[k], max, &v[k]);

__syncthreads();

call_2 (y, v, max, z);
free (v);

我部分意识到可以通过使用threadIdx, blockIdx, and gridDim的组合来删除for循环,但我特别不确定特别是该问题是否包含也使用函数调用的函数调用

1 个答案:

答案 0 :(得分:-1)

那么有两个可能的答案,虽然我没有勇气为你搜索所有这些,但我仍然会给你一个答案,因为你似乎被公然忽略了。 :/

<强>首先
最近的CUDA API和nvidia架构支持CUDA中的函数调用甚至递归。我不确定它是如何工作的,因为我自己从未使用它,但你可能想研究它。 (或者做一些Vulkan,因为它看起来非常有趣并且也支持它。)

可以帮助你:https://devtalk.nvidia.com/default/topic/493567/cuda-programming-and-performance/calling-external-kernel-from-cuda/ 和其他相关关键字的东西。 :D 另一方面..
在解决简单的问题时,特别是如果像我一样,你宁愿花时间编程而不是研究和学习一些随机的API,那么你总是可以使用你所使用的语言的基础来使用更原始的解决方案。

在你的情况下,我只是简单地调用函数来调用一个CUDA内核,因为它看起来很容易。

是的,是的,它可能包括一些复制粘贴,如果有多个函数调用...这并不重要,如果它可以让你轻松有效地解决一个简单的问题,并做更多的事情生产性。

int index = blockIdx.x * blockDim.x + threadIdx.x;
int stride = blockDim.x * gridDim.x;
for (int k=index; k<max; k += stride)
    call_2 (x[k], y[k], max, &v[k]); // Insert call_2 code here instead.

另一种解决方法是,当你确信你的数据足够大,即使从CPU和RAM传递代码和数据到GPU,性能也会有很大的提升,就是要有多个“波浪” cuda内核调用。

你准备第二个波浪时让第一个波浪进程,然后在完成的第一个波浪上启动。

它基本上等同于最近的CUDA实现提供的其他更智能的结构,所以你可能会发现更聪明的事情与一些研究,但再次......取决于你的优先级。

但是,手动内联函数非常棒。 :D
*大部分都没有,但它可以非常方便