我试图优化一些最初在Fortran中编写的代码。在OpenCL中写入全局内存
算法涉及在多个迭代上对大阵列(~27百万个细胞)进行操作。每个细胞可以在一次迭代过程中独立评估。然而,由于在t + 1完成的计算取决于在t完成的计算结果,所以迭代不能并行化。
粗糙,简化不平行的伪代码示例:
for (t=0; t<tmax; t++)
{
A = A + B;
B = B + A /2;
}
其中A和B是大阵列。
目前,我已经通过调用EnqueueNDRangeKernel在宿主C++代码中的一个循环中实现了这一点。因为我需要前一次迭代的结果,所以我每次都写入全局内存。
每次迭代执行2700万次全局内存写入会杀死我的性能。我有两个我正在玩的内核版本;与Fortran相比,版本1的速度快了2.5倍;版本2快4倍。
我已经尝试摆弄算法,以及做指针(版本2)的东西。
我的问题如下:有没有办法避免这个全局内存写chokepoint?
谢谢!
请求代码:
呼叫在C++:
NDRange global(nxp1*ny*nz);
NDRange local(nz);
for (w=0; w<100; w++)
{
queue.enqueueNDRangeKernel(kernA, NullRange, global, local);
queue.enqueueBarrierWithWaitList();
queue.enqueueNDRangeKernel(kernB, NullRange, global, local);
}
queue.finish();
仁:
__kernel void kernA(__global double *A, __global double *B)
{
int i = get_global_id(0);
double A_l;
A_l = A[i];
double B_l;
B_l = B[i];
A_l = A_l + B_l;
A[i] = A_l; //if this line is removed, everything goes much faster.
}
__kernel void kernB(__global double *A, __global double *B)
{
int i = get_global_id(0);
double A_l;
A_l = A[i];
double B_l;
B_l = B[i];
B_l = B_l + A_l/2;
B[i] = B_l; //if this line is removed, everything goes much faster.
}
我已经简化内核代码澄清算法的缘故。但是这个想法是我基于B更新A;然后我基于A更新B,重复这个过程进行几次迭代。
为了计算新的A或B的“(i,j)”条目,是否需要引用除了旧的A和B的“(i,j)”条目之外的任何东西?如果不是,那么除了第一次迭代的输入和最后一次迭代的输出之外,您不需要使用全局内存,并且可以在单个内核调用中计算多次迭代。 – user57368 2014-09-26 18:28:54
我只需要知道前一次迭代中的旧A(i)和B(i)。你是否打算在内核中运行迭代循环?这会保持迭代的顺序吗? – Vlad 2014-09-26 18:39:37
细胞是由什么组成的?单一的价值? int,float,double或其他东西?你可以在同一个内核调用中计算多于一次的迭代。 – mfa 2014-09-26 18:43:07