使用CUDA模拟管道程序

时间:2016-04-03 01:44:09

标签: cuda gpu gpgpu gpu-programming

假设我有两个数组AB以及一个kernel1,它们通过将数组分成不同的块来对两个数组(例如向量加法)进行一些计算,然后写入部分结果为Ckernel1然后继续这样做,直到处理完数组中的所有元素。

unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
unsigned int gridSize = blockDim.x*gridDim.x;

//iterate through each chunk of gridSize in both A and B
while (i < N) {
     C[i] = A[i] + B[i];
     i += gridSize;
}

说,现在我想在kernel2和另一个数据数组C上发布D。无论如何我可以在计算kernel2中的第一个块之后立即开始C 吗?从本质上讲,kernel1 管道会导致kernel2。依赖树看起来像这样

       Result
       /  \
      C    D
    /  \    
   A    B     

我考虑过使用CUDA流但不确定如何使用。也许将主机纳入计算中?

1 个答案:

答案 0 :(得分:1)

是的,您可以使用CUDA streams来管理此类情景中的顺序和依赖关系。

假设您希望重叠复制和计算操作。这通常意味着您将输入数据分解为&#34;块&#34;然后将块复制到设备,然后启动计算操作。每个内核启动都在&#34; chunk&#34;数据。

我们可以通过主机代码中的循环来管理流程:

// create streams and ping-pong pointer
cudaStream_t stream1, stream2, *st_ptr;
cudaStreamCreate(&stream1); cudaStreamCreate(&stream2);
// assume D is already on device as dev_D
for (int chunkid = 0; chunkid < max; chunkid++){
  //ping-pong streams
  st_ptr = (chunkid % 2)?(&stream1):(&stream2);
  size_t offset = chunkid*chunk_size;
  //copy A and B chunks
  cudaMemcpyAsync(dev_A+offset, A+offset, chksize*sizeof(A_type), cudaMemcpyHostToDevice, *st_ptr);
  cudaMemcpyAsync(dev_B+offset, B+offset, chksize*sizeof(B_type), cudaMemcpyHostToDevice, *st_ptr);
  // then compute C based on A and B
  compute_C_kernel<<<...,*st_ptr>>>(dev_C+offset, dev_A+offset, dev_B+offset, chksize);
  // then compute Result based on C and D
  compute_Result_kernel<<<...,*st_ptr>>>(dev_C+offset, dev_D, chksize);
  // could copy a chunk of Result back to host here with cudaMemcpyAsync on same stream
  }
发送到同一流的所有操作都保证在设备上按顺序(即顺序)执行。发给单独流的操作可以重叠。因此,上述顺序应该:

  • 将一大块A复制到设备
  • 将一大块B复制到设备
  • 启动内核以从A和B计算C
  • 启动内核以计算来自C和D的结果

将对每个块重复上述步骤,但是将向备用流发出连续的块操作。因此,块2的复制操作可以与来自块1等的内核操作重叠。

您可以通过查看有关CUDA流的演示文稿了解更多信息。 Here就是一个例子。

较新的设备(Kepler和Maxwell)应该非常灵活地了解在设备上看到操作重叠所需的程序问题顺序。较旧(费米)设备可能对发布订单敏感。您可以阅读有关here

的更多信息