Cuda - 3D块和网格尺寸混淆 - 另一个

Cuda - 3D block & grid dimension confusion - Another one

本文关键字:另一个 网格 3D Cuda      更新时间:2023-10-16

在下面的简单示例中,我使用cudaMalloc3D在设备上分配内存,并将我的3D数据的每个体素增加1,这很好,只要我使用对称的3D体积。

主机代码如下所示:

int main(void)
{
    typedef float PixelType;
    // Set up test data
    dim3  image_dimensions = dim3(32, 32, 32);
    size_t num_elements = image_dimensions.x * image_dimensions.y * image_dimensions.z;
    PixelType *image_data = new float[num_elements];
    for(int i = 0; i < num_elements; ++i)
    {
        image_data[i] = float(i);
    }
    // Allocate 3D memory on the device
    cudaExtent volumeSizeBytes = make_cudaExtent(sizeof(PixelType) * image_dimensions.x, image_dimensions.y, image_dimensions.z);
    cudaPitchedPtr devicePitchedPointer;
    cudaMalloc3D(&devicePitchedPointer, volumeSizeBytes);
    cudaMemset3D(devicePitchedPointer, 1.0f, volumeSizeBytes);
    // Copy image data from the host to the device
    cudaMemcpy3DParms copy_params_host_to_device = {0};
    copy_params_host_to_device.srcPtr = make_cudaPitchedPtr((void *)image_data, sizeof(PixelType) * image_dimensions.x, image_dimensions.y, image_dimensions.z);
    copy_params_host_to_device.dstPtr = devicePitchedPointer;
    copy_params_host_to_device.extent = volumeSizeBytes;
    copy_params_host_to_device.kind   = cudaMemcpyHostToDevice;
    cudaMemcpy3D(&copy_params_host_to_device);
    // Kernel Launch Configuration
    dim3 threads_per_block = dim3(8, 8, 8);
    dim3 blocks_per_grid = dim3((image_dimensions.x + threads_per_block.x - 1) / threads_per_block.x, (image_dimensions.y + threads_per_block.y - 1) / threads_per_block.y, (image_dimensions.z + threads_per_block.z - 1) / threads_per_block.z);
    extract_patches_from_image_data<<<blocks_per_grid, threads_per_block>>>(devicePitchedPointer, image_dimensions);
    cudaDeviceSynchronize();
    // Copy image data back from the device to the host
    cudaMemcpy3DParms copy_params_device_to_host = {0};
    copy_params_device_to_host.srcPtr = devicePitchedPointer;
    copy_params_device_to_host.dstPtr = make_cudaPitchedPtr((void *)image_data, sizeof(PixelType) * image_dimensions.x, image_dimensions.y, image_dimensions.z);
    copy_params_device_to_host.extent = volumeSizeBytes;
    copy_params_device_to_host.kind   = cudaMemcpyDeviceToHost;
    cudaMemcpy3D(&copy_params_device_to_host);
    // Check image data
    for(int i = 0; i < num_elements; ++i)
    {
        std::cout << "Element: " << i << " - " << image_data[i] << std::endl;
    }
    // Free Memory
    cudaFree(devicePitchedPointer.ptr);
    delete [] image_data;
}

所有值递增对应的内核:

__global__ void extract_patches_from_image_data(cudaPitchedPtr devicePitchedPointer, dim3 image_dimensions)
{
    // Index Calculation
    int x = threadIdx.x + blockDim.x * blockIdx.x;
    int y = threadIdx.y + blockDim.y * blockIdx.y;
    int z = threadIdx.z + blockDim.z * blockIdx.z;
    // Get attributes from device pitched pointer
    char     *devicePointer  =   (char *)devicePitchedPointer.ptr;
    size_t    pitch          =   devicePitchedPointer.pitch;
    size_t    slicePitch     =   pitch * image_dimensions.y;
    // Loop over image data
    if(z < image_dimensions.z)
    {
        char *current_slice_index = devicePointer + z * slicePitch;
        if(y < image_dimensions.y)
        {
            // Get data array containing all elements from the current row
            PixelType *current_row = (PixelType *)(current_slice_index + y * pitch);
            if(x < image_dimensions.x)
            {
                current_row[x] = current_row[x] + 1.0f;
                // Get values of all all neighbors
            }
        }
    }
}

只要我保持我的image_dimensions对称,例如(32,32,32),一切都很好。当我尝试使用(32,32,33)时,它工作得很好,直到体素33759,以下值保持不变。我现在的问题是我应该如何调整我的代码,以使用非对称数据。

  1. 我建议做适当的cuda错误检查任何时候你有cuda代码的问题,虽然它不会在这里解决问题。
  2. 正在传递floatcudaMemset3D。如果你打算将每个浮点数设置为这个值,那就行不通了。cudaMemset3D的工作原理类似主机memset函数。它接受unsigned char值并设置unsigned char数量。您不能使用此方法将float值正确地初始化为1.0f。但这也不是问题的症结所在。
  3. 您没有正确使用make_cudaPitchedPtr功能。请查看文档。最后两个参数应该分别是xy维度,而不是yz。在你的代码中有两个这样的实例。

通过修改make_cudaPitchedPtr

的两个用法,我能够使您的代码正确运行。