CUDA:atomicAdd需要太多时间,序列化线程

时间:2012-07-22 04:35:14

标签: cuda shared-memory atomic elapsedtime prefix-sum

我有一个内核进行一些比较并决定两个对象是否发生碰撞。我想将碰撞对象的id存储到输出缓冲区。我不想在输出缓冲区中有间隙。我想将每个碰撞记录到输出缓冲区中的唯一索引。

所以我在共享内存(本地和)中创建了一个原子变量,并在全局内存中创建了一个原子变量(全局和)。下面的代码显示了找到碰撞时共享变量的递增。我现在没有在全局内存中递增原子变量的问题。

__global__ void mykernel(..., unsigned int *gColCnt) {
    ...

    __shared__ unsigned int sColCnt;
    __shared__ unsigned int sIndex;

    if (threadIdx.x == 0) {
        sColCnt = 0;
    }

    __syncthreads();

    unsigned int index = 0;
    if (colliding)
        index = atomicAdd(&sColCnt, 1); //!!Time Consuming!!

    __syncthreads();

    if (threadIdx.x == 0)
        sIndex = atomicAdd(gColCnt, sColCnt);

    __syncthreads();

    if (sColCnt + sIndex > outputSize) { //output buffer is not enough
        //printf("Exceeds outputsize: %d + %d > %d\n", sColCnt, sIndex, outputSize);
        return;
    }

    if (colliding) {
        output[sIndex + index] = make_uint2(startId, toId);
    }
}

我的问题是,当许多线程尝试增加原子变量时,它们会被序列化。在写一些像prefix-sum这样的东西之前,我想问一下是否有办法有效地完成这项工作。

我内核的经过时间从13毫秒增加到44毫秒,因为有一行。

我找到了一个前缀和示例代码,但由于NVIDIA的讨论板已关闭,其引用的链接失败。 https://stackoverflow.com/a/3836944/596547


编辑: 我已将代码的结尾添加到上面。实际上我确实有一个层次结构。为了看到每个代码行的影响,我设置了每个对象相互碰撞的场景,极端情况和另外一个大约没有物体碰撞的极端情况。

最后,我将共享原子变量添加到全局变量(gColCnt),以通知外部有关冲突的数量并找到正确的索引值。我想我必须以任何方式使用atomicAdd。

2 个答案:

答案 0 :(得分:1)

考虑使用并行流压缩算法,例如thrust::copy_if

答案 1 :(得分:1)