Concurrency 在OpenCL中创建线程网格

Concurrency 在OpenCL中创建线程网格,concurrency,opencl,Concurrency,Opencl,我为OpenCL编写了一个内核,其中我将3D数组的所有元素初始化为->I*I*I+j*j*j。我现在在创建线程网格来初始化元素(同时)时遇到了问题。我知道我现在的代码只使用了3个线程,我如何扩展它呢 请帮忙。我是OpenCL的新手,所以任何建议或解释都很方便。谢谢 这是代码: _kernel void initialize ( int X; int Y; int Z; _global float*A) { // Get global position in X direction int di

我为OpenCL编写了一个内核,其中我将3D数组的所有元素初始化为->I*I*I+j*j*j。我现在在创建线程网格来初始化元素(同时)时遇到了问题。我知道我现在的代码只使用了3个线程,我如何扩展它呢

请帮忙。我是OpenCL的新手,所以任何建议或解释都很方便。谢谢

这是代码:

_kernel void initialize (
int X;
int Y;
int Z;
_global float*A) {

// Get global position in X direction
int dirX = get_global_id(0);
// Get global position in Y direction
int dirY = get_global_id(1);
// Get global position in Z direction
int dirZ = get_global_id(2);

int A[2000][100][4];
int i,j,k;
for (i=0;i<2000;i++)
{
    for (j=0;j<100;j++)
    {
        for (k=0;k<4;k++)
        {
            A[dirX*X+i][dirY*Y+j][dirZ*Z+k] = i*i*i + j*j*j;
        }
    }
}
}
\u内核无效初始化(
int X;
int-Y;
intz;
_全球浮动*A){
//获得X方向的全局位置
int dirX=获取全局id(0);
//获得Y方向的全局位置
int dirY=get_global_id(1);
//获取Z方向的全局位置
int dirZ=get_global_id(2);
INTA[2000][100][4];
int i,j,k;
对于(i=0;i
  • 创建缓冲区以将输出“A”存储在调用(主机)代码中。它作为指针传递给内核,这在上面的函数定义中是正确的。但是,您不需要在内核函数中再次声明它,因此请删除行
    int A[2000][100][4];

  • 您可以大大简化代码。使用3D全局ID将3D索引指示到每个工作项的数组中,您可以如下更改循环(假设对于给定的i和j,沿Z的所有元素都应该具有相同的值):

然后,在调用代码中创建全局工作大小为2000x100x4的内核

  • 实际上,这需要安排大量的工作项,因此如果全局(一维)工作大小为2000,并且内核中有一个循环,您可能会获得更好的性能,例如:

    __kernel void initialize (__global float* A) {
      // cast required so that kernel compiler knows the array dimensions
      __global float (*a)[2000][100][4] = A;
    
      // Get global position in X direction
      int i = get_global_id(0);
    
      for (j=0;j<100;j++) {
        for (k=0;k<4;k++) {
          (*a)[i][j][k] = i*i*i + j*j*j;
        }
      }
    }
    
    \uuuuu内核无效初始化(\uuuu全局浮点*A){
    //强制转换是必需的,以便内核编译器知道数组维度
    __全球浮动(*a)[2000][100][4]=a;
    //获得X方向的全局位置
    int i=获取全局id(0);
    
    对于(j=0;jIt看起来像是此代码将A作为_全局浮点*传入,然后将其重新声明为int数组,这本身就是私有的。这是故意的吗?嗨,除了隐藏boiler96突出显示的“A”变量外,为什么说您只使用3个线程?您的工作组大小有3个维度(X、Y和Z)因此,我怀疑您创建的线程(工作项)远远不止3个在您的调用代码中。您希望最终输出数组的大小是多少?2000x100x4还是这些维度的倍数?@boiler96我认为这是我犯的错误,它应该是一个数组。您能帮我更正一下吗?@JamesBeilby我的最终输出数组应该是2000x100x4。只是一个相关问题。如果“a”不是定义的矩阵,编译器如何知道每个维度的大小?我想知道a[I*100*4+j*4+k]是访问矩阵的正确方法。前两个项目是这个问题的一个很好的答案,但我不同意你的最后一个项目。最好只编写尽可能简单的代码,不定义工作组大小,让OpenCL SDK处理准备优化的代码。除非你是在请注意,我已经发现这段代码效率低下,我认为这样修改它不是一个好主意。@DarkZeros,+1很好,我在答案中添加了一个cast来满足这一点。另一种方法是按照您的建议使用一维数组,可能会将维度作为参数传递给内核。@Oak,+1,因为它是har我不同意K.I.S.S.原则,但在同样的基础上,你可能会问为什么要使用OpenCL:宿主语言中的实现可能更简单,而不是混淆缓冲区和内核!因为大多数人使用OpenCL优化宿主代码,而不是纯粹的“理论”OpenCL,我想说的是,他们应该始终牢记实现,例如,对调度程序的欣赏、可用内存的多少、内存在哪里以及如何访问。我的观点不是简单,而是性能:一般来说,SDK在设置工作组大小和迭代工作项方面比您做得更好,除非ss您正在根据您要针对的具体体系结构进行自定义。只需为每个逻辑工作分配一个工作项,并让SDK对其进行优化-例如,它可能会选择自己添加这些您添加的循环,也可能不会。
    __kernel void initialize (__global float* A) {
      // cast required so that kernel compiler knows the array dimensions
      __global float (*a)[2000][100][4] = A;
    
      // Get global position in X direction
      int i = get_global_id(0);
    
      for (j=0;j<100;j++) {
        for (k=0;k<4;k++) {
          (*a)[i][j][k] = i*i*i + j*j*j;
        }
      }
    }