Cuda 在块之间划分3D内核的工作

Cuda 在块之间划分3D内核的工作,cuda,Cuda,我有这样一个3D内核,我目前在一个块上运行: // The two following variables are set elsewhere in the program. // I give them possible value here for demonstration purposes. int* N = {14, 5, 1}; int L = 2; // N's size - 1 int idx = blockIdx.x * blockDim.x + threadIdx.x; i

我有这样一个3D内核,我目前在一个块上运行:

// The two following variables are set elsewhere in the program.
// I give them possible value here for demonstration purposes.
int* N = {14, 5, 1};
int L = 2; // N's size - 1

int idx = blockIdx.x * blockDim.x + threadIdx.x;
int idy = blockIdx.x * blockDim.y + threadIdx.y;
int idz = blockIdx.x * blockDim.z + threadIdx.z;

int idxInc = idx + 1; // for not to waste threads whose idx = 0
if (idxInc >= 1 && idxInc <= L)
{
    if (idy < N[idxInc])
    {       
        if (idz < N[idxInc-1])
        {
            dw[ idxInc ][ idy ][ idz ] = 0;
        }
    }
}
//以下两个变量在程序的其他地方设置。
//为了便于演示,我在这里给出了它们可能的值。
int*N={14,5,1};
int L=2;//N的尺寸-1
int idx=blockIdx.x*blockDim.x+threadIdx.x;
intidy=blockIdx.x*blockDim.y+threadIdx.y;
int idz=blockIdx.x*blockDim.z+threadIdx.z;
int-idxInc=idx+1;//用于不浪费idx=0的线程

如果(idxInc>=1&&idxInc,下面是一个简单的示例代码,我认为它与您所描述的内容大致相同:

#include <stdio.h>

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)

// for simplicity assume grid is an even multiple of blocksizes
#define XSIZE 1024
#define YSIZE 14
#define ZSIZE 2
#define TSIZE (XSIZE*YSIZE*ZSIZE)
#define BLKX 16
#define BLKY 14
#define BLKZ 2


#define IDX(x,y,z) ((z*(XSIZE*YSIZE))+(y*XSIZE)+x)

typedef float mytype;

__global__ void mykernel(mytype *data){

  int idx = threadIdx.x + blockDim.x*blockIdx.x;
  int idy = threadIdx.y + blockDim.y*blockIdx.y;
  int idz = threadIdx.z + blockDim.z*blockIdx.z;

  if ((idx < XSIZE)&&(idy < YSIZE)&&(idz < ZSIZE))
    data[IDX(idx,idy,idz)] = (mytype)idx;
  if ((idx==127)&&(idy==13)&&(idz==1)) printf("BONJOUR\n");
}

int main(){


// for simplicity assume grid is an even multiple of blocksizes
  dim3 block(BLKX, BLKY, BLKZ);
  dim3 grid(XSIZE/BLKX, YSIZE/BLKY, ZSIZE/BLKZ);

  mytype *h_data, *d_data;

  h_data=(mytype *)malloc(TSIZE*sizeof(mytype));
  if (h_data == 0) {printf("malloc fail\n"); return 1;}
  cudaMalloc((void **)&d_data, TSIZE*sizeof(mytype));
  cudaCheckErrors("cudaMalloc fail");

  for (int x=0; x<XSIZE; x++)
    for (int y=0; y<YSIZE; y++)
      for (int z=0; z<ZSIZE; z++)
        h_data[IDX(x,y,z)] = (mytype)0;

  cudaMemcpy(d_data, h_data, TSIZE*sizeof(mytype), cudaMemcpyHostToDevice);
  cudaCheckErrors("cudaMemcpy fail");

  mykernel<<<grid, block>>>(d_data);
  cudaDeviceSynchronize();
  cudaCheckErrors("kernel fail");

  cudaMemcpy(h_data, d_data, TSIZE*sizeof(mytype), cudaMemcpyDeviceToHost);
  cudaCheckErrors("cudaMemcpy fail");


  for (int x=0; x<XSIZE; x++)
    for (int y=0; y<YSIZE; y++)
      for (int z=0; z<ZSIZE; z++)
        if(h_data[IDX(x,y,z)] != (mytype)x) {printf("data check fail at (x,y,z) = (%d, %d, %d), was: %f, should be: %f\n", x,y,z, h_data[IDX(x,y,z)], x); return 1;}
  printf("Data check passed!\n");


  return 0;
}
当我运行它时,我得到:

BONJOUR
Data check passed!

你是说问题的总范围是由{2,5,14}threadblock结构定义的吗?如果是的话,这是一个小问题。扩展它的方法是提出一个更大的数据集。在这种情况下,我看到的大多数代码只是选择一些方便的threadblock大小,比如{8,8,8}然后将整个3D域划分为大小相同的块,每个线程在一个元素上运行。就像在1D的情况下一样,我们应该在内核代码中进行线程检查,根据有效的数据索引检查线程索引。在域的边缘上会有一些浪费的线程;没关系。下面是我上面描述的一个示例。int*N={2, 5, 14}这只是我使用的一个例子,因为我发现考虑小数据更容易。如果你还记得的话,我仍在尝试并行化我的神经网络…中心值5是隐藏层的神经元数量。它可能设置为128或1024。用户必须选择此值。但层的数量2不太可能改变。输入层14的神经元数量永远不会改变。因此,如果我为这样一组数据选择一个对称块:{2,1024,14},它可能会导致大量线程浪费…无论如何,我的代码不起作用,即使是一个对称块。如果我将128个神经元放入隐藏层->N={14,128,1},然后选择方便的{8,8,8}块,我需要启动16个块。结果只有一个0的小正方形,其大小为…8x8x8!其余的块没有初始化。我想这与线程ID计算有关。我正在搜索,但我的呼吸被打断…这个->“如果(idx==127&&idy==127&&idz==127)printf(“HELLO\n”);”是可以的,它被打印出来了。但是这个->“如果”(idx==0&&idy==127&&idz==13)printf(“你好”;“由于某种原因,不会显示!为什么有一个线程{127127}但没有线程{01227,13}???我疯了!你真是太好了!好吧,让我问你几点,因为我从你的每一行中都学到了东西!首先,我不知道有人可以启动3D网格。现在,ids计算是有意义的,一切都初始化了!我刚刚添加了使用ceil进行网格尺寸计算:(ceil(XSIZE/BLKX)、ceil(YSIZE/BLKY)、ceil(ZSIZE/BLKZ)。接下来,使用连续向量而不是3D数组。我被告知这更快。我猜从3D数组访问案例意味着3次内存访问,这比绝对id计算和内存访问慢。是这样吗?我还被告知我应该选择块维度为包裹大小的倍数。我猜用于不加载和卸载内部只有两个线程的包装。您使用16*14*2,这是32的倍数。但是,如果我希望网格中有2*128*128个线程,我可以选择块大小为2*22*22,这将导致每个块的多线程数为非32,但网格为1*6*6个块,或者选择块大小为1*32*32,它将启动2*4*grid!理论上哪种解决方案最好?完整包装的块更多?或不完整包装的块更少?是的,您可以在网格大小计算中使用
ceil
。为了清晰/简单起见,我只是省略了它。1D阵列更容易在主机和设备之间来回复制。我认为在访问方面没有任何区别速度/时间。是,块尺寸应该是经纱大小的倍数。我们还需要X维度中的许多相邻线程,并且我们希望X是我们的“快速变化的维度”,以便实现聚结,即有效的内存访问。因此考虑重新排序数据存储,使X成为与我所做的最大维度。32×32×1(x,y,z)比2*22*22要好。
nvcc -arch=sm_20 -o t159 t159.cu
BONJOUR
Data check passed!