2012-01-06 75 views
7

这是我想要转换为openCL的循环。openCL减少,并传递2d数组

for(n=0; n < LargeNumber; ++n) {  
    for (n2=0; n2< SmallNumber; ++n2) { 
     A[n]+=B[n2][n]; 
    }               
    Re+=A[n];  
} 

这就是我到目前为止,虽然,我知道这是不正确的,缺少一些东西。

__kernel void openCL_Kernel(__global int *A, 
         __global int **B, 
         __global int *C, 
         __global _int64 Re, 
            int D) 
{ 

int i=get_global_id(0); 
int ii=get_global_id(1); 

A[i]+=B[ii][i]; 

//barrier(..); ? 

Re+=A[i]; 

} 

我是这种类型的东西的完整初学者。首先我知道我不能将全局双指针传递给openCL内核。如果可以的话,在发布解决方案之前请等待几天左右,我想为自己弄清楚这一点,但如果您能帮助我指出正确的方向,我将不胜感激。

+1

“我无法将全局双指针传递给openCL内核”您选择的单词让我困惑。您可以传递一个双指针(例如“__global double * A”)。您无法传递2D指针(例如“__global int ** B”)。 – vocaro 2012-01-06 19:56:22

+0

你有没有考虑将程序分成两个独立的内核(顺序执行),一个用于内部循环,另一个用于外部循环? – vocaro 2012-01-06 19:59:06

回答

11

关于你传递两个指针的问题:通常通过将整个矩阵(或你正在处理的任何东西)拷贝到一个连续的内存块中来解决这类问题,如果这些块有不同的长度传递另一个数组,包含各行的偏移量(因此您的访问权限看起来像B[index[ii]+i])。

现在为了减少到Re:因为你没有提到你正在做什么类型的设备,我将假设它的GPU。在这种情况下,我会避免在同一个内核中进行缩减,因为它会像发布它一样缓慢(您将不得不将序列化访问数千个线程的Re(以及访问A[i]))。 相反,我会写想内核,总结所有B[*][i]A[i],并把从A还原成Re在另一个内核,并做到在几个步骤,这是您使用它进行操作n元素,并将它们降低到类似的减少内核(或者任何其他数字),然后你反复调用这个内核,直到你下降到一个元素,这是你的结果(我把这个描述刻意模糊,因为你说你想知道自己的想法)

作为旁注:您意识到原始代码并不完全具有良好的内存访问模式?假设B比较大(并且由于第二维而比A大得多),让内部循环遍历外部索引会产生大量的cachemisses。这是更糟糕移植到GPU,这大约是一致内存访问非常敏感,当

所以重新排序像这样可以大量提高性能:

for (n2=0; n2< SmallNumber; ++n2) 
    for(n=0; n < LargeNumber; ++n)  
    A[n]+=B[n2][n]; 
for(n=0; n < LargeNumber; ++n)             
    Re+=A[n];  

这是格外真实,如果你有一个编译器是擅长自动矢量化,因为它可能能够矢量化该构造,但是对于原始代码来说这是不太可能的(并且如果它不能证明AB[n2]不能引用相同的存储器,它可以将原始代码转换成这个)。

+0

谢谢!这让我有很多想法。 – MVTC 2012-01-07 19:33:06