这是我想要转换为openCL的循环。
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内核。如果可以的话,在发布解决方案之前等待几天左右,我想为自己解决这个问题,但如果你能帮我指出正确的方向,我将不胜感激。
答案 0 :(得分:11)
关于传递双指针的问题:通常通过将整个矩阵(或您正在处理的任何内容)复制到一个连续的内存块中来解决这种问题,如果块具有不同的长度,则传递另一个数组,其中包含各行的偏移量(因此您的访问权限类似于B[index[ii]+i]
)。
现在你的减少到Re
:因为你没有提到你正在使用什么样的设备,我将假设它的GPU。在这种情况下,我会避免在同一个内核中进行减少,因为它会像你发布它一样慢(你必须序列化对成千上万个线程Re
的访问(以及访问A[i]
也是。
相反,我会编写想要的内核,它将所有B[*][i]
加到A[i]
中,并将A
中的减少量放到另一个内核中的Re
中并分几步完成,就是你使用对n
元素进行操作的简化内核,并将其缩减为n / 16
(或任何其他数字)。然后你迭代地调用那个内核,直到你归结为一个元素,这是你的结果(我说这个描述故意模糊,因为你说你想要自己想出来)。
作为旁注:您意识到原始代码并不完全具有良好的内存访问模式?假设B
相对较大(并且由于第二维而大得多A
)内部循环遍历外部索引会产生大量的高速缓存。移植到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];
如果您有一个擅长自动向量化的编译器,这是特别的,因为它可能能够对该构造进行向量化,但是对于原始代码来说它是不太可能的(如果它不能证明A
和B[n2]
无法引用相同的内存,无法将原始代码转换为此内容。