通常我们在编写kernel中最关键的就是获取内存中,数组的下标id,从而对数组中每个元素做并行计算,
通常我们设置global size的参数,与输入计算的数组数据的长度一一对应。
发起kernel运算的API:
cl_int enqueueNDRangeKernel(
const Kernel& kernel,
const NDRange& offset,
const NDRange& global,
const NDRange& local = NullRange,
const VECTOR_CLASS<Event>* events = NULL,
Event* event = NULL)
我们会设置数据数组的核心参数: global 维度 size local 维度 size
这和kernel函数中获取index的API一一对应
get_global_id(dim)
get_global_size(dim)
get_group_id(dim)
get_local_id(dim)
get_local_size(dim)
dim是维度参数
看我前面给的最简单的数组相加kernel,vectorAdd,
输入的数据为三个一维的16正整数数据,两个数组按照index,分别相加,最后保存到第三个数组里。
我这边只设置了global 为 NDRange(16),默认local = NullRange这里如果不设置local的值,则local的default值就等于NDRange(16)
因为是一维数据,所以dim的取值只有0是有效值
get_global_id(0) 取值 [0, 15]
get_global_size(0) == 16
get_local_id(0) 取值 [0, 15]
get_local_size(0) == 16
那么work group的个数只有一个,因为global size 等于 local size
get_group_id(0)的取值只能是0
所以,遍历id = get_global_id(0),即可完成两个数组的相加。
上面的简单的对我之前的例子做一个简单的解释, 接下来看看GPU架构管理设计:
网上找的二维数据的示意图(侵删)
如图所示:
基础kernel的运算单位:work item;每一个work item上运行一次kernel;
人为设置local size,虚拟地把work item组织成work group;
所有work group 组合成了整个gobal, 三维的情况下,切豆腐了解一哈。
遵循这个计算公式:get_global_id(dim) = get_local_size(dim)*get_group_id(dim) + get_local_id(dim);
举两个例子:
1.例如上我用来示例地例子,设置global = NDRange(16),local = NDRange(8),则
参数dim的取值为0
get_global_id(0) 取值 [0, 15]
get_global_size(0) == 16
get_local_id(0) 取值 [0, 7]
get_local_size(0) == 8
16被分成了两个8份的work group,所以
get_group_id(0) 取值 [0,1]
2.上面的图片二维数据例子,设置global = NDRange(16,16),local = NDRange(4,4),则
dim取值为[0, 1]
get_global_id(0) 取值 [0, 15],get_global_id(1) 取值 [0, 15],
get_global_size(0) == 16,get_global_size(1) == 16,
get_local_id(0) 取值 [0, 3],get_local_id(1) 取值 [0, 3]
get_local_size(0) == 4,get_local_size(1) == 4,
16x16被分成了4x4份的work group,所以
get_group_id(0) 取值 [0,3],get_group_id(1) 取值 [0,3
综上,local数值设定一般必为global数值整除,这样就可以通过以上五个API有规律的获取数据序号关系,从而获取到对应的数据值.
作为一个杠精,那么问题来了,local设置的数值不能整除时,会怎么样呢?有兴趣的自己跑程序的时候瞎搞一下就知道了,我试了计算会失效。