是否可以使用opencl数据并行内核对大小为N的向量求和,而不进行部分求和技巧?
假设您可以访问16个工作项并且您的向量大小为16.不会让内核执行以下操作
__kernel void summation(__global float* input, __global float* sum)
{
int idx = get_global_id(0);
sum[0] += input[idx];
}
当我尝试这个时,sum变量不会被更新,但只会被覆盖。我已经阅读了一些关于使用障碍的内容,并且我尝试在上面的求和之前插入障碍,它会以某种方式更新变量,但它不会重现正确的总和。
答案 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更好。