需要CUDA设备内存事务

时间:2012-07-10 19:01:43

标签: memory cuda gpu shared-memory

我写了一些小的cuda代码来了解共享内存传输事务的全局内存。代码如下:

#include <iostream>
using namespace std;

__global__ void readUChar4(uchar4* c, uchar4* o){
  extern __shared__ uchar4 gc[];
  int tid = threadIdx.x;
  gc[tid] = c[tid];
  o[tid] = gc[tid];
}

int main(){
  string a = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
  uchar4* c;
  cudaError_t e1 = cudaMalloc((void**)&c, 128*sizeof(uchar4));
  if(e1==cudaSuccess){
    uchar4* o;
    cudaError_t e11 = cudaMalloc((void**)&o, 128*sizeof(uchar4));

    if(e11 == cudaSuccess){
      cudaError_t e2 = cudaMemcpy(c, a.c_str(), 128*sizeof(uchar4), cudaMemcpyHostToDevice);
      if(e2 == cudaSuccess){
        readUChar4<<<1,128, 128*sizeof(uchar4)>>>(c, o);
        uchar4* oFromGPU = (uchar4*)malloc(128*sizeof(uchar4));
        cudaError_t e22 = cudaMemcpy(oFromGPU, o, 128*sizeof(uchar4), cudaMemcpyDeviceToHost);
        if(e22 == cudaSuccess){
          for(int i =0; i < 128; i++){
            cout << oFromGPU[i].x << " ";
            cout << oFromGPU[i].y << " ";
            cout << oFromGPU[i].z << " ";
            cout << oFromGPU[i].w << " " << endl;

          }
        }
        else{
          cout << "Failed to copy from GPU" << endl;
        }
      }
      else{
        cout << "Failed to copy" << endl;
      }
    }
    else{
      cout << "Failed to allocate output memory" << endl;
    }
  }
  else{
    cout << "Failed to allocate memory" << endl;
  }
  return 0;
}

此代码只是将数据从设备内存复制到共享内存并返回到设备内存。我有以下三个问题:

  1. 在这种情况下,从设备内存到共享内存的转移是否可以保证进行4次内存事务?我相信它取决于cudaMalloc如何分配内存;如果内存以偶然的方式分配,使得数据分散在内存上,那么将需要4次以上的内存事务。但是,如果cudaMalloc以128字节块的形式分配内存或者它连续分配内存,那么它不应该超过4次内存事务。
  2. 上述逻辑是否也适用于将数据从共享内存写入设备内存,即传输将在4次内存事务中完成。
  3. 此代码是否会导致银行冲突。我相信如果线程按顺序分配ID,则此代码不会导致存储体冲突。但是,如果计划在同一个warp中运行线程32和64,则此代码可能会导致存储体冲突。

1 个答案:

答案 0 :(得分:2)

在您提供的代码中(此处重复),编译器将完全删除共享内存并加载,因为它们不会对代码执行任何必要或有益的操作。

 __global__ void readUChar4(uchar4* c, uchar4* o){
  extern __shared__ uchar4 gc[];
  int tid = threadIdx.x;
  gc[tid] = c[tid];
  o[tid] = gc[tid];
}

假设您对共享内存做了一些事情,因此没有消除,那么:

  1. 此代码中从全局内存加载和存储将为每个warp(假设Fermi或更高版本的GPU)采用一个事务,因为它们每个线程只有32位(uchar4 = 4 * 8位) (每个warp总共128个字节)。 cudaMalloc连续分配内存。
  2. 1的答案也适用于商店,是的。
  3. 此代码中没有银行冲突。 warp中的线程始终是连续的,第一个线程是warp大小的倍数。因此,线程32和64将永远不会处于相同的warp中。由于您正在加载和存储32位数据类型,并且存储区为32位宽,因此没有冲突。