OpenCL数据并行求和成变量

时间:2016-01-29 07:55:46

标签: c++ arrays sum opencl

是否可以使用opencl数据并行内核对大小为N的向量求和,而不进行部分求和技巧?

假设您可以访问16个工作项并且您的向量大小为16.不会让内核执行以下操作

    __kernel void summation(__global float* input, __global float* sum)
{
    int idx = get_global_id(0);

    sum[0] += input[idx];
}

当我尝试这个时,sum变量不会被更新,但只会被覆盖。我已经阅读了一些关于使用障碍的内容,并且我尝试在上面的求和之前插入障碍,它会以某种方式更新变量,但它不会重现正确的总和。

2 个答案:

答案 0 :(得分:3)

让我试着解释为什么sum[0]被覆盖而不是更新。

在16个工作项的情况下,有16个线程同时运行。现在sum[0]是一个单独的内存位置,由所有线程共享,并且行sum[0] += input[idx]由16个线程中的每一个同时运行。

现在,sum[0] += input[idx](我认为)扩展指令会执行sum[0]的读取,然后在将结果写回input[idx]之前将sum[0]添加到sum[0]

当多个线程正在读取和写入同一共享内存位置时,将会有data race。所以会发生什么:

  • 所有线程可以在任何其他线程之前读取sum[0]的值 将更新后的结果写回sum[0],在这种情况下是最终结果 input[idx]的结果将是该帖子的sum[0]的值 执行速度最慢的。因为每次都会有所不同, 如果您多次运行该示例,您应该看到不同的 结果。
  • 或者,在这种情况下,一个线程可能执行得稍慢一些 另一个线程可能已经将更新的结果写回 这个慢速线程在sum[0]之前读var fooApp = angular.module("foo", []) ,在这种情况下就是var BodyController = function($scope) { $scope.message = "Hi Angular!" } fooApp.controller("BodyController", BodyController); 将使用多个线程的值进行添加,但不是 所有主题。

那你怎么能避免这个呢?

选项1 - Atomics(更糟糕的选择):

如果另一个线程正在共享内存位置上执行操作,则可以使用atomics强制所有线程阻塞,但这显然会导致性能损失,因为您正在使并行进程串行(并且会产生)并行化的成本 - 例如在主机和设备之间移动内存以及创建线程。)

选项2 - 减少(更好的选项):

最佳解决方案是减少阵列,因为您可以最有效地使用并行性,并且可以提供O(log(N))性能。以下是使用OpenCL进行简化的概述:Reduction Example

答案 1 :(得分:0)

选项3(最糟糕的是)

    __kernel void summation(__global float* input, __global float* sum)
{
    int idx = get_global_id(0);
    for(int j=0;j<N;j++)
    {
        barrier(CLK_GLOBAL_MEM_FENCE| CLK_LOCAL_MEM_FENCE);
        if(idx==j)
         sum[0] += input[idx];
        else
         doOtherWorkWhileSingleCoreSums();

    }
}

使用主流gpu,这应该与pentium mmx一样慢。这就像在单个核心上进行计算,并以较慢的方式为其他核心提供其他工作。

这种cpu设备可能比gpu更好。