我正在测试以下代码,以便在OpenCL 2.0中使用work_groups内置函数执行并行数组元素添加。 (在这种情况下为inclusive_add和reduce_add)
kernel void(global const float *input,
global float *sum,
local float *scratch)
{
uint local_id = get_local_id(0);
scratch[local_id] = work_group_inclusive_add(input[get_global_id(0)]);
if (local_id == get_local_size(0)-1)
sum[get_group_id(0)] = work_group_reduce_add(scratch[local_id]);
}
如果我用0到15的浮点数组测试它,步长为1,则global_size = 16,local_size = 4我希望结果为" 6.0 22.0 38.0 54.0"如果我选择CPU作为设备,这可以正常工作。
但是只要我选择GPU并运行相同的代码,我就会得到" 0.0 4.0 8.0 12.0" (这只是每个工作组第一个位置的元素)
我错过了什么吗?
我试图做但却没有影响事情的事情:
添加"屏障(CLK_LOCAL_MEM_FENCE)"在" if"
更改本地大小和/或数组大小/全局大小。
注意:
我使用clEnqueueWriteBuffer传递输入数组,然后使用clEnqueueReadBuffer读取总和
CPU:i5 6200u
GPU:英特尔高清显卡520
(是的,他们支持OpenCL 2.0,我可以成功构建内核,ioc64传递-cl-std = CL2.0,就像我在运行时构建程序一样)
答案 0 :(得分:2)
由于您使用的是work_group_reduce_add
错误的方式,因此会得到不同的结果。
a中的所有工作项必须遇到此内置函数 工作组执行内核。
当您致电work_group_reduce_add
时,情况并非如此。
您需要从那里删除if
语句。通过添加只允许一个工作项访问它的if语句,您只需计算一个值的总和。这将归还给你。
在work_group_scan_inclusive_add
后,数字应如下:
w1: 0,1,2,3 -> 0,1,3,6
w2: 4,5,6,7 -> 4,9,15,22
w3: 8,9,10,11 -> 8,17,27,38
w4: 12,13,14,15 -> 12,25,39,54
work_group_reduce_add
之后:
w1: 10
w2: 50
w3: 90
w4: 130
规范中的第二件事:
注意:不保证浮点运算的顺序 work_group_reduce_,work_group_scan_inclusive_和 work_group_scan_exclusive_内置函数 half,float和double数据类型。这些浮点的顺序 对于给定的工作组,操作也是不确定的。
所以我计算的包容性扫描后的结果可能不一定是相同的,这就是你在GPU返回的内容(GPU正在返回0,4,8,12,这恰好是每个缓冲区的最后一个值) )。
总结:在work_group_reduce_add
之前删除if语句应该解决问题。