了解GPU中具有多个线程的CUDA程序的执行模式

时间:2014-10-10 21:29:10

标签: cuda gpgpu

以下是我对CUDA线程执行模式的理解。如果特定线程满足条件,它将执行内核。通常,每个线程的索引和访问都是使用其线程和块ID完成的。但是,当我遇到下面这段代码时,我跌跌撞撞。至于正确性,这段代码给出了完全正确的结果。

__global__ void kernel0(int *a)
{
    int b0 = blockIdx.x;
    int t0 = threadIdx.x;
    __shared__ int shared_a[32][33];


    for (int g5 = 0; g5 <= 96; g5 += 32) {
      for (int c0 = 0; c0 <= min(31, -32 * b0 + 99); c0 += 1)
        for (int c1 = t0; c1 <= min(32, -g5 + 99); c1 += 32)
          shared_a[c0][c1] = a[(32 * b0 + c0) * 100 + (g5 + c1)];

      __syncthreads();

      if (32 * b0 + t0 <= 99)
        for (int c2 = 0; c2 <= min(31, -g5 + 98); c2 += 1)
          shared_a[t0][c2 + 1] = (shared_a[t0][c2] + 5);

      __syncthreads();

      if (((t0 + 31) % 32) + g5 <= 98)
        for (int c0 = 0; c0 <= min(31, -32 * b0 + 99); c0 += 1)
          a[(32 * b0 + c0) * 100 + (((t0 + 31) % 32) + g5 + 1)] = shared_a[c0][((t0 + 31) % 32) + 1];

      __syncthreads();

    }
}

我的问题是32块的块大小中的哪个thread-id执行前3个for-loop&#39; s?

1 个答案:

答案 0 :(得分:1)

简短回答

每个线程都会执行for循环,但只有索引在[0,min(31,-32 * b0 + 99)] [t0,c1&lt; = min(32,-g5 + 99) ]在内部陈述中做一些工作,即

shared_a[c0][c1] = a[(32 * b0 + c0) * 100 + (g5 + c1)]

关于映射机制

您必须为每个线程分配其对应工作的方式是索引。例如,以下语句将仅由每个块的线程0执行:

if( threadIdx.x == 0){
// some code
}

虽然这个只由线程执行,而索引0是一维网格:

if( threadIdx.x + blockIdx.x*blockDim.x == 0){
// some code
}

此代码(来自简单的数组缩减)也可用于说明此类行为:

for( unsigned int s = 1; s < blockDim.x; s *= 2){
    int index = 2*s*tid;

    if( index < blockDim.x){
        sdata[index] += sdata[index + s];
    }
    __syncthreads();
}

块中的所有线程都执行for循环,并且所有线程都有自己的索引变量值。然后,if语句阻止某些线程执行添加。最后,添加仅由具有线程号“index”的线程执行。

如您所见,这使得一些线程处于空闲状态而其他线程可能需要做很多工作(负载不平衡),因此需要在整个网格中实现均匀的工作负载以最大限度地提高性能。

学习资料。

起初这可能有些令人困惑,所以我建议您阅读CUDA工具包中包含的CUDA C编程指南。使用矩阵 - 矩阵乘法,向量加法和向量约简。

一本非常全面的指南是David B. Kirk和Wen-mei W. Hwu撰写的“大规模并行处理程序编程”一书。