可以在OpenCL

时间:2016-02-05 08:33:58

标签: opencl barrier

这是我的第一篇文章。我会尽量保持简短,因为我珍惜你的时间。这个社区对我来说太不可思议了。

我正在学习OpenCL,并希望从以下算法中提取一点并行性。我只会向您展示我正在处理的部分,我也尽可能地简化了部分。

1)输入:两个长度为(n)的1D数组:A,B和n的值。也值C [0],D [0]。

2)输出:两个长度为(n)的1D阵列:C,D。

C[i] = function1(C[i-1])
D[i] = function2(C[i-1],D[i-1])

所以这些是递归定义,但C&对于给定的i值,D可以并行完成(它们显然更复杂,以便有意义)。一个天真的想法是为以下内核创建两个工作项:

__kernel void test (__global float* A, __global float* B, __global float* C,
                    __global float* D, int n, float C0, float D0) {
    int i, j=get_global_id(0);

    if (j==0) {
       C[0] = C0;
       for (i=1;i<=n-1;i++) {
          C[i] = function1(C[i-1]);
          [WAIT FOR W.I. 1 TO FINISH CALCULATING D[i]];
       }
       return;
    }
    else {
       D[0] = D0;
       for (i=1;i<=n-1;i++) {
          D[i] = function2(C[i-1],D[i-1]);
          [WAIT FOR W.I. 0 TO FINISH CALCULATING C[i]];
       }
       return;
    }
}

理想情况下,两个工作项(数字0,1)中的每一个都会进行一次初始比较,然后输入各自的循环,同步每次迭代。现在给出GPU的SIMD实现,我认为这不起作用(工作项将等待所有内核代码),但是是否可以将这种类型的工作分配给两个CPU内核并使其按预期工作?在这种情况下,障碍是什么?

2 个答案:

答案 0 :(得分:1)

这可以在opencl中实现,但是就像其他答案所说的那样,你最多只能限制为2个线程。

应该使用包含两个工作项的单个工作组调用我的函数版本。

__kernel void test (__global float* A, __global float* B, __global float* C, __global float* D, int n, float C0, float D0)
{
    int i;
    int gid = get_global_id(0);

    local float prevC;
    local float prevD;

    if (gid == 0) {
        C[0] = prevC = C0;
        D[0] = prevD = D0;
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    for (i=1;i<=n-1;i++) {
        if(gid == 0){
            C[i] = function1(prevC);
        }else if (gid == 1){
            D[i] = function2(prevC, prevD);
        }

        barrier(CLK_LOCAL_MEM_FENCE);
        prevC = C[i];
        prevD = D[i];
    }
}

这应该在任何opencl硬件上运行。如果您不关心保存所有C和D值,只需在两个浮点数而不是整个列表中返回prevC和prevD。由于为所有读取和写入中间值而坚持较低的高速缓存级别(即本地存储器),这也会使其快得多。本地内存增强也应该适用于所有opencl硬件。

那么有必要在GPU上运行吗?不是为了并行性。你被困在2个线程中。但是如果你不需要返回C和D的所有值,你可能会看到显着的加速,因为GPU的内存要快得多。

所有这些都假定function1和function2并不过分复杂。如果是这样,只需坚持使用CPU - 可能还有其他多处理技术,如OpenMP。

答案 1 :(得分:0)

你的情况下的依赖是完全线性/递归的(我需要i-1)。甚至不像其他问题(减少,总和,排序等)的对数。因此,这个问题不适合SIMD设备。

你能做的最好就是在CPU中采用双线程方法。线程1将&#34;生成&#34;线程2的数据(C值)。

一种非常天真的方法,例如:

Thread 1:
for(){
    ProcessC(i);
    atomic_inc(counter); //This function should unlock
}

Thread 2:
for(){
    atomic_dec(counter); //This function should lock
    ProcessD(i);
}

例如,可以使用计数信号量来实现atomic_incatomic_dec