代码之家  ›  专栏  ›  技术社区  ›  user366312

如何计算每个网格的块?

  •  0
  • user366312  · 技术社区  · 2 年前

    假设我有一个GPU,它允许 MAX_THREAD 每个块的线程数。

    此外,假设它允许 MAX_BLOCK_DIM x、y和z的每个网格维度上每个网格的块数。

    如果 最大线程(_T) =1024,如果 dim3 threads_per_block 设置为[32,8,4],如32*8*4=1024,我如何计算的每个维度 dim3 blocks_per_grid 这样我就可以像下面这样启动内核了?

    my_kernel<<<blocks_per_grid, threads_per_block>>>(... ... ...);
    

    例如

    dim3 threads_per_block(x, y, z);
    dim3 blocks_per_grid(xx, yy, zz);
    

    我能计算一下的值吗 xx , yy zz 从…起 x , y z 分别地

    如果没有,正确的方法是什么?

    0 回复  |  直到 2 年前
        1
  •  1
  •   Homer512    2 年前

    首先定义栅格尺寸。这取决于你在做什么。假设您有一张尺寸为1024x768的图像,然后进行逐像素计算。那么你的网格自然会 dim3(1024, 768, 1) 。如果你有几帧视频,它可能是 dim3(width, height, frames)

    您的块尺寸由内核决定。如果您没有特定的需要,我建议您不要使用非常大的块,如1024。这可能导致低效利用,因为诸如 __syncthreads() 或者内核的结束导致相当多的线程等待几个掉队者。当有疑问时,坚持使用128x1x1或16x16x1之类的小东西。

    考虑到这一点,您可以计算块。

    dim3 grid(1024, 768, 1);
    dim3 blockdim(16, 16, 1);
    dim3 blocks((grid.x + blockdim.x - 1) / blockdim.x,
                (grid.y + blockdim.y - 1) / blockdim.y,
                (grid.z + blockdim.z - 1) / blockdim.z);
    

    这个计算是四舍五入的除法。这样可以确保在网格尺寸不能被块尺寸整除时启动足够的块。不利的一面是,现在您可能会启动比所需更多的线程。实际上,你的网格被填充到块尺寸的倍数。有多种方法可以解决这一问题,例如确保阵列维度始终是16的倍数。然而,最简单的方法是简单地检查是否超出范围。

    __global__ void kernel(int xdim, int ydim, int zdim)
    {
        int x_idx = blockIdx.x * blockDim.x + threadIdx.x;
        int y_idx = blockIdx.y * blockDim.y + threadIdx.y;
        int z_idx = blockIdx.z * blockDim.z + threadIdx.z;
        if(x_idx < xdim && y_idx < ydim && z_idx < zdim) {
            do_something();
        }
    }
    

    通常,如果沿Y和Z轴的块尺寸为1,则可以跳过Y和Z尺寸的检查。

    另一种方法是只启动GPU上可以同时运行的线程,然后在内核内进行循环。与大型网格的实际工作相比,这具有降低启动开销比例的好处,因为所有索引计算只需要完成一次,并且通过将部分计算从循环体中提取出来,可以进行更多优化。

    __global__ void kernel(int xdim, int ydim, int zdim)
    {
        int x_start = blockIdx.x * blockDim.x + threadIdx.x;
        int y_start = blockIdx.y * blockDim.y + threadIdx.y;
        int z_start = blockIdx.z * blockDim.z + threadIdx.z;
        int x_stride = gridDim.x * blockDim.x;
        int y_stride = gridDim.y * blockDim.y;
        int z_stride = gridDim.z * blockDim.z;
        for(int z_idx = z_start; z_idx < zdim; z_idx += z_stride)
            for(int y_idx = y_start; y_idx < ydim; y_idx += y_stride)
                for(int x_idx = x_start; x_idx < xdim; x_idx += x_stride)
                    do_something();
    }