[英]Method to do final sum with reduction
我接受了在这个链接上解释的第一个问题的延续。
我提醒你,我想应用一种能够用OpenCL进行多次减少的方法(我的GPU设备只支持OpenCL 1.2)。 我需要计算一个数组的总和减少来检查主循环的每次迭代的收敛标准,
目前,我只做了一次减少(即一次迭代)的版本。 在这个版本中,为简单起见,我使用了一个顺序CPU循环来计算每个部分和的总和并得到sum的最终值。
根据我在先例中的建议,我的问题是我不知道如何通过再次调用NDRangeKernel
函数(即第二次执行内核代码)来执行最终总和。
实际上,通过第二次调用,我总是会遇到同样的问题,即获得部分和的总和(本身是从第一次调用NDRangeKernel
计算出来的):它似乎是一个递归问题。
让我们从上图中举例说明:如果输入数组大小为10240000
且WorkGroup size
为16
,则得到10000*2^10/2^4 = 10000*2^6 = 640000 WorkGroups
。
所以在第一次调用之后,我获得了640000 partial sums
:如何处理所有这些部分总和的最终结果? 如果我再次调用内核代码,例如WorkGroup size = 16
和global size = 640000
,我将得到nWorkGroups = 640000/16 = 40000 partial sums
,所以我必须再次调用内核代码并重复此过程直到nWorkGroups < WorkGroup size
。
也许我不太了解第二阶段,大部分内核代码来自“两阶段缩减”( 在此链接上,我认为这是搜索输入数组的最小值的情况 )
__kernel
void reduce(__global float* buffer,
__local float* scratch,
__const int length,
__global float* result) {
int global_index = get_global_id(0);
float accumulator = INFINITY;
// Loop sequentially over chunks of input vector
while (global_index < length) {
float element = buffer[global_index];
accumulator = (accumulator < element) ? accumulator : element;
global_index += get_global_size(0);
}
// Perform parallel reduction
...
如果有人能够解释上面代码片段内核代码的作用。
是否与第二阶段的减少有关系,即最终的结果?
如果您不了解我的问题,请随时向我询问更多详细信息。
谢谢
如评论中所述:声明
如果输入数组大小为10240000且WorkGroup大小为16,则得到10000 * 2 ^ 10/2 ^ 4 = 10000 * 2 ^ 6 = 640000个工作组。
是不正确的。 您可以选择“任意”工作组大小和“任意”数量的工作组。 这里选择的数字可以针对目标设备定制。 例如,设备可能具有某种本地存储器大小。 可以使用clDeviceGetInfo
查询:
cl_ulong localMemSize = 0;
clDeviceGetInfo(device, CL_DEVICE_LOCAL_MEM_SIZE,
sizeof(cl_ulong), &localMemSize, nullptr);
考虑到每个工作组将需要的事实,这可用于计算本地工作组的大小
sizeof(cl_float) * workGroupSize
本地内存的字节数。
类似地,工作组的数量可以从其他设备特定参数导出。
关于减少本身的关键点是工作组大小不限制可以处理的数组的大小 。 我对整个算法的理解也有些困难,所以我试着在这里解释一下,希望一些图像可能胜过千言万语:
如您所见,工作组的数量和工作组大小是固定的,与输入数组长度无关:即使我在示例中使用了3个大小为8的工作组(全局大小为24) ,可以处理长度为64的数组。 这主要是由于第一个循环,它只是遍历输入数组,其“步长”等于全局工作大小(此处为24)。 其结果将是对于每个24个线程之一累计值。 然后这些并行减小。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.