【问题标题】:CUDA In-place Transpose ErrorCUDA 就地转置错误
【发布时间】:2013-01-06 04:15:43
【问题描述】:

我正在实施一个用于转置图像的 CUDA 程序。我创建了 2 个内核。第一个内核进行了不合适的转置,并且适用于任何图像大小。

然后我创建了一个内核,用于就地转置方形图像。但是,输出不正确。图像的下三角形被转置,但上三角形保持不变。生成的图像在对角线上有一个类似楼梯的图案,楼梯每一步的大小等于我用于内核的 2D 块大小。

异地内核:

如果 src 和 dst 不同,则适用于任何图像尺寸。

template<typename T, int blockSize>
__global__ void kernel_transpose(T* src, T* dst, int width, int height, int srcPitch, int dstPitch)
{
    __shared__ T block[blockSize][blockSize];

    int col = blockIdx.x * blockSize + threadIdx.x;
    int row = blockIdx.y * blockSize + threadIdx.y;

    if((col < width) && (row < height))
    {
        int tid_in = row * srcPitch + col;
        block[threadIdx.y][threadIdx.x] = src[tid_in];
    }

    __syncthreads();

    col = blockIdx.y * blockSize + threadIdx.x;
    row = blockIdx.x * blockSize + threadIdx.y;

    if((col < height) && (row < width))
    {
        int tid_out = row * dstPitch + col;
        dst[tid_out] = block[threadIdx.x][threadIdx.y];
    }
}

就地内核:

template<typename T, int blockSize>
__global__ void kernel_transpose_inplace(T* srcDst, int width, int pitch)
{
    __shared__ T block[blockSize][blockSize];

    int col = blockIdx.x * blockDim.x + threadIdx.x;
    int row = blockIdx.y * blockDim.y + threadIdx.y;

    int tid_in = row * pitch + col;
    int tid_out = col * pitch + row;

    if((row < width) && (col < width))
        block[threadIdx.x][threadIdx.y] = srcDst[tid_in];

    __threadfence();

    if((row < width) && (col < width))
        srcDst[tid_out] = block[threadIdx.x][threadIdx.y];
}

包装函数:

int transpose_8u_c1(unsigned char* pSrcDst, int width,int pitch)
{
    //pSrcDst is allocated using cudaMallocPitch

    dim3 block(16,16);
    dim3 grid;
    grid.x = (width + block.x - 1)/block.x;
    grid.y = (width + block.y - 1)/block.y;

    kernel_transpose_inplace<unsigned char,16><<<grid,block>>>(pSrcDst,width,pitch);

    assert(cudaSuccess == cudaDeviceSynchronize());

    return 1;
}

示例输入和错误输出:

我知道这个问题与 in-place 转置的逻辑有关。这是因为我的不合适的转置内核可以完美地用于不同的源和目标,如果我将源和目标的单个指针传递给它也会给出相同的错误结果。

我做错了什么?帮助我纠正就地内核。

【问题讨论】:

  • 你能添加图片吗,之前,之后,以及之后的错误。它有助于问题的可视化。另外,如果您可以包含异地内核的代码
  • @ks6g10... 两者都添加了。嗯... after-correct 是什么不是很明显吗?。

标签: cuda transpose in-place


【解决方案1】:

您的就地内核正在覆盖图像中的数据,这些数据随后将被另一个线程拾取以用于其转置操作。因此对于方形图像,您应该在覆盖目标数据之前对其进行缓冲,然后将目标数据放置在适当的转置位置。由于我们使用这种方法有效地为每个线程执行 2 个副本,因此只需要使用一半的线程。像这样的东西应该可以工作:

template<typename T, int blockSize>
__global__ void kernel_transpose_inplace(T* srcDst, int width, int pitch)
{

    int col = blockIdx.x * blockDim.x + threadIdx.x;
    int row = blockIdx.y * blockDim.y + threadIdx.y;

    int tid_in = row * pitch + col;
    int tid_out = col * pitch + row;

    if((row < width) && (col < width) && (row<col)) {

        T temp = srcDst[tid_out];

        srcDst[tid_out] = srcDst[tid_in];
        srcDst[tid_in] = temp;
        }
}

【讨论】:

  • 非常感谢。它确实解决了问题。但有一件事令人困惑?我不是已经在共享内存中缓冲数据了吗?为了确保所有线程都缓冲了数据,我使用了threadfence()
  • 我想你可能对__threadfence() 有疑问,这是一种障碍,但它不是设备范围的障碍。它只是特定线程的障碍。如果它同时充当所有线程的屏障,那么您的方法可能会起作用。但是除了通过内核启动/退出之外,CUDA 中没有全局障碍。您不妨阅读description。正如你所拥有的那样,它只保证在继续执行之前,块中的其他线程可以看到对共享内存的写入。
  • 是的,我阅读了__threadfence() 的描述,从其文档的第二点开始,我一直认为整个网格就像__syncthreads()
  • 关键字是“由调用线程制作”。这意味着它只会阻塞它所在的任何线程的执行,并且只会阻塞执行,直到满足这两个可见性条件。它与__syncthreads() 有很大不同,正如我所说,CUDA 中没有全局同步机制。与 __syncthreads() 不同,它确实强制多个线程在任何线程执行可以继续之前到达屏障。
  • 大家好,这似乎不适用于非方阵。为什么会这样?
猜你喜欢
  • 2014-12-13
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
  • 2015-11-14
  • 2011-02-10
  • 1970-01-01
  • 2020-08-25
  • 1970-01-01
相关资源
最近更新 更多