Opencl 全局工作大小和本地工作大小对应用程序逻辑有影响吗?
我试图理解OpenCL中所有不同维度的参数是如何组合在一起的。若我的问题不清楚,部分是因为一个结构良好的问题需要一些我并没有的答案 work_dim、global_work_size和local_work_size如何共同创建内核中使用的执行空间?例如,如果我将work_dim 2设置为2,那么我可以Opencl 全局工作大小和本地工作大小对应用程序逻辑有影响吗?,opencl,Opencl,我试图理解OpenCL中所有不同维度的参数是如何组合在一起的。若我的问题不清楚,部分是因为一个结构良好的问题需要一些我并没有的答案 work_dim、global_work_size和local_work_size如何共同创建内核中使用的执行空间?例如,如果我将work_dim 2设置为2,那么我可以 get_global_id(0); get_global_id(1); 我可以使用全局工作大小将这两个维度分成n个工作组,对吗?所以如果我把全局的大小变成这样 那么每个维度将有4个工作组,总共8
get_global_id(0);
get_global_id(1);
我可以使用全局工作大小将这两个维度分成n个工作组,对吗?所以如果我把全局的大小变成这样
那么每个维度将有4个工作组,总共8个?但是,作为一个初学者,我只使用全局id作为索引,所以不管怎样,只有全局id才是问题所在。你可以告诉我,我对这一切都很困惑,所以你能提供的任何帮助都会……帮助
既然您自己说您对执行空间中涉及的概念有点困惑,那么在回答您的问题之前,我将尝试对它们进行总结,并给出一些示例 螺纹/工作项组织在一个NDRange中,该NDRange可被视为1、2、3 DIM的网格。 NDRange主要用于将每个线程映射到每个线程都必须处理的数据块。因此,每个线程都应该被唯一标识,并且线程应该知道它是哪一个线程以及它在NDRange中的位置。还有内置函数的工作项。所有线程都可以调用这些函数,以向它们提供有关自身及其所在区域的信息 尺寸: 如前所述,NDRange最多可以有3个维度。因此,如果按这种方式设置尺寸:
size_t global_work_size[2] = { 4, 4 };
这并不意味着每个维度将有4个工作组,总共8个,但您的NDRange中将有4*4,即16个线程。这些螺纹将排列成“正方形”,侧面为4个单元。使用uint get\u work\u dim()
函数,工作项可以知道nRange由多少个维度组成
全球规模:
线程还可以使用size\u t get\u global\u size(uint D)
查询特定维度的NDRange有多大。因此,他们可以知道“直线/正方形/矩形/立方体”的范围有多大
全局唯一标识符:
由于该组织,每个线程都可以用对应于特定维度的索引进行唯一标识。因此,螺纹(2,1)指的是2D范围第三列第二行中的螺纹。内核中使用函数size\u t get\u global\u id(uint D)
来查询线程的id
工作组(或本地)大小:
NDRange可以拆分为称为工作组的较小组。这是您所指的本地工作大小,它也(逻辑上)最多有3个维度。请注意,对于低于2.0的OpenCL版本,给定维度中的NDRange大小必须是该维度中工作组大小的倍数。因此,为了保留您的示例,因为在维度0中我们有4个线程,所以维度0中的工作组大小可以是1、2、4,但不能是3。与全局大小类似,线程可以使用size\u t get\u local\u size(uint D)
查询本地大小
本地唯一标识符:
有时,在工作组中可以唯一标识线程是很重要的。因此函数size\u t get\u local\u id(uint D)
。注意前一句中的“内”。具有本地id(1,0)的线程将是其工作组(2D)中唯一具有此id的线程。但是具有本地id(1,0)的线程数量将与NDRange中的工作组数量相同
组数:
谈到组,有时线程可能需要知道有多少组。这就是函数size\u t get\u num\u groups(uint D)
存在的原因。请注意,您必须再次将感兴趣的尺寸作为参数传递
每个组还具有一个id:
…您可以使用函数size\u t get\u group\u id(uint D)
在内核中查询。请注意,组ID的格式将类似于线程的格式:最多包含3个元素的元组
总结:
总而言之,如果您的2Dn范围的全局工作大小为(4,6),本地工作大小为(2,2),则表示:
- 维度0中的全局大小将为4
- 维度1中的全局大小将为6
- 维度0中的本地大小(或工作组大小)将为2
- 维度1中的本地大小(或工作组大小)将为2
- 维度0中的线程全局ID的范围为0到3
- 维度1中的线程全局ID的范围为0到5
- 维度0中的线程本地ID的范围为0到1
- 维度1中的线程本地ID的范围为0到1
- NDRange中的线程总数将为4*6=24
- 工作组中的线程总数为2*2=4
- 工作组总数为(4/2)*(6/2)=6
- 维度0中的组ID的范围为0到1
- 维度1中的组ID的范围为0到2
- 只有一个线程将使用全局id(0,0),但将有6个线程使用本地id(0,0),因为有6个组
size_t global_work_size[2] = { 4, 4 };
//in is a 24 int array, result is a 6 int array, temp is a 4 int array
kernel void foo(global int *in, global int *result, local int *temp){
//use vectors for conciseness
int2 globalId = (int2)(get_global_id(0), get_global_id(1));
int2 localId = (int2)(get_local_id(0), get_local_id(1));
int2 groupId = (int2)(get_group_id (0), get_group_id (1));
int2 globalSize = (int2)(get_global_size(0), get_global_size(1));
int2 locallSize = (int2)(get_local_size(0), get_local_size(1));
int2 numberOfGrp = (int2)(get_num_groups (0), get_num_groups (1));
//Read from global and store to local
temp[localId.x + localId.y * localSize.x] = in[globalId.x + globalId.y * globalSize.x];
//Sync
barrier(CLK_LOCAL_MEM_FENCE);
//Only the threads with local id (0, 0) sum elements up
if(localId.x == 0 && localId.y == 0){
int sum = 0;
for(int i = 0; i < locallSize.x * locallSize.y ; i++){
sum += temp[i];
}
//store result in global
result[groupId.x + numberOfGrp.x * groupId.y] = sum;
}
}