C ++ 17引入了许多支持并行执行的新算法,特别是std::reduce是std::accumulate的并行版本,它允许non-deterministic
行为non-commutative
行为,例如作为浮点加法。我想使用OpenCL 2实现reduce算法。
英特尔有一个示例here,它使用OpenCL 2 work group
内核函数来实现std::exclusive_scan OpenCL 2内核。以下是基于英特尔exclusive_scan
示例的总和浮点数的内核:
kernel void sum_float (global float* sum, global float* values)
{
float sum_val = 0.0f;
for (size_t i = 0u; i < get_num_groups(0); ++i)
{
size_t index = get_local_id(0) + i * get_enqueued_local_size(0);
float value = work_group_reduce_add(values[index]);
sum_val += work_group_broadcast(value, 0u);
}
sum[0] = sum_val;
}
上面的内核有效(或似乎!)。但是,exclusive_scan
要求work_group_broadcast
函数将一个work group
的最后一个值传递给下一个,而此内核只需要将work_group_reduce_add的结果添加到sum_val
,所以atomic add
更合适。
OpenCL 2提供支持atomic_int
的{{1}}。使用atomic_int的上述内核的整数版本是:
atomic_fetch_add
OpenCL 2还提供kernel void sum_int (global int* sum, global int* values)
{
atomic_int sum_val;
atomic_init(&sum_val, 0);
for (size_t i = 0u; i < get_num_groups(0); ++i)
{
size_t index = get_local_id(0) + i * get_enqueued_local_size(0);
int value = work_group_reduce_add(values[index]);
atomic_fetch_add(&sum_val, value);
}
sum[0] = atomic_load(&sum_val);
}
,但 支持atomic_float
。
实现OpenCL2内核对浮点数求和的最佳方法是什么?
答案 0 :(得分:1)
kernel void sum_float3 (global float* sum, global float* values)
{
float sum_partial = work_group_reduce_add(sum[get_global_id(0)]);
if(get_local_id(0)==0)
values[get_group_id(0)] = sum_partial;
}
这具有将数据写入sum的零索引元素的竞争条件,所有工作组正在进行相同的计算,这使得该O(N * N)而不是O(N)并且需要超过1100毫秒完成1M元素数组和。
对于相同的1-M元素数组,这个(global = 1M,local = 256)
values: 1.0 1.0 .... 1.0 1.0
sum_float2
sum: 256.0 256.0 256.0
sum_float3
values: 65536.0 65536.0 .... 16 items total to be summed by cpu
后跟这个(global = 4k,local = 256)
{{1}}除了第三步,
在几毫秒内做同样的事情。第一个将每个组加入到它们的group-id相关项中,第二个内核将它们加到16个值中,这16个值可以很容易地用CPU(微秒或更小)求和(作为第三步)。
程序的工作方式如下:
{{1}}
如果你需要使用原子,你应该尽量少做。最简单的例子可以是使用局部原子来对每个组的许多值求和,然后使用每个组的单个全局原子函数进行最后一步以添加所有值。我现在还没有为OpenCL准备好C ++设置,但是当你使用具有相同内存资源的多个设备(可能是流模式或SVM)时,我认为OpenCL 2.0原子会更好/或使用C ++ 17函数的 CPU 。如果你没有同时在同一区域上计算多个设备,那么我认为这些新的原子只能在已经运行的OpenCL 1.2原子之上进行微优化。我没有使用这些新的原子,所以把所有这些都当作一粒盐。