不连贯的商店

时间:2011-06-02 18:34:24

标签: cuda

为什么这个内核会生成不连贯的商店

__global__ void reverseArrayBlock(int *d_out, int *d_in)
{
    int inOffset  = blockDim.x * blockIdx.x;
    int outOffset = blockDim.x * (gridDim.x - 1 - blockIdx.x);
    int in  = inOffset + threadIdx.x;
    int out = outOffset + (blockDim.x - 1 - threadIdx.x);
    d_out[out] = d_in[in];
}

而且这个不是

__global__ void reverseArrayBlock(int *d_out, int *d_in)
{
    extern __shared__ int s_data[];

    int inOffset  = blockDim.x * blockIdx.x;
    int in  = inOffset + threadIdx.x;

    // Load one element per thread from device memory and store it 
    // *in reversed order* into temporary shared memory
    s_data[blockDim.x - 1 - threadIdx.x] = d_in[in];

    // Block until all threads in the block have written their data to shared mem
    __syncthreads();

    // write the data from shared memory in forward order, 
    // but to the reversed block offset as before

    int outOffset = blockDim.x * (gridDim.x - 1 - blockIdx.x);

    int out = outOffset + threadIdx.x;
    d_out[out] = s_data[threadIdx.x];
}

我知道第二个是使用共享内存。但是当我看到d_out的指标时,它们在两个内核中看起来都是一样的。你能帮我理解一下吗?

2 个答案:

答案 0 :(得分:3)

合并要求地址遵循warp中的“base + tid”模式,其中tid是线程索引的缩写。换句话说,随着tid增加,地址也增加。您的评论称此为“转发订单”。在第一个内核中,生成地址,使得当tid增加时,地址减少,即访问以“向后顺序”。

答案 1 :(得分:0)

在我们开始之前,您需要了解对共享内存的写入比写入全局内存要便宜得多。

考虑到这一点,我们假设我们正在反转阵列1-> 32

方法一这样做: 写作的同时 线程1从位置x读取,线程2从(x + 1)读取,线程3从位置读取(x + 2)...线程32从位置读取(x + 31)。

你可以在2(如果是对齐的)或3(如果是非对齐的)读取中读取整个内存块,因为操作是在半块(16个线程)的块中完成的。

写作时 线程1写入位置(y + 31),线程2写入(y + 30),线程3写入位置(y + 29)...线程32写入位置(y)。

虽然他们正在写入连续的大块内存,但它们的顺序相反。除非你使用的是一些最新的硬件(即使它使用它我很怀疑),它将需要32次写入来执行操作。

对于第二种情况,您正在对共享内存进行32次反向写入,对共享内存执行32次反向读取,这样做并不昂贵。

现在您已经按相反的顺序读取了数据,您可以按正确的顺序写入全局内存。

线程1写入位置y,线程2写入位置y + 1,依此类推。

最重要的是,您节省了执行32(metod 1)所需的时间 - 3(方法2)= 29次写入全局内存。