【问题标题】:Concurrency of CUDA default stream with created streamsCUDA 默认流与创建的流的并发
【发布时间】:2015-03-16 00:06:36
【问题描述】:

我以这种方式创建了流:

cudaStream_t stream0;
cudaStream_t stream1;
cudaStreamCreate( &stream0);
cudaStreamCreate( &stream1);

我运行像

这样的内核函数
singlecore<<<1,1>>>(devL2,1000);
singlecore<<<1,1,0,stream0>>>(devL2,1000);

当前没有执行这两个内核。但是如果我将stream1 中的第一个内核执行为:

singlecore<<<1,1,0,stream1>>>(devL2,1000);
singlecore<<<1,1,0,stream0>>>(devL2,1000);

它们将在当前执行。

我想知道默认流中的内核函数目前是否无法执行。

【问题讨论】:

    标签: cuda parallel-processing


    【解决方案1】:

    是的,对默认流发出的 cuda 命令存在限制。参考implicit synchronization上的C编程指南部分:

    “如果主机线程在它们之间发出以下任一操作,则来自不同流的两个命令不能同时运行: ... •任何CUDA命令到默认流, "

    因此,作为一般经验法则,对于重叠的复制和计算操作,将所有此类操作编程到一组非默认流中是最简单的。有一点漏洞(您已经发现),可能会与默认流(和其他流)中发出的命令重叠,但也需要仔细了解默认流和其他流之间的限制仔细注意您发出命令的顺序。 A good example 在 C 编程指南中进行了解释。通读“重叠行为”部分。

    在您的第一个示例中,发给默认流的内核阻止了发给另一个流的内核的执行。在您的第二个示例中,您可以具有并发性,因为向非默认流发出的内核不会阻止向默认流发出的内核的执行。

    【讨论】:

      【解决方案2】:

      我想根据新发行的 CUDA 7.0 更新 Robert Crovella 的答案,截至 2015 年 3 月,该版本处于候选发布版本中。

      在 CUDA 7.0 中,默认流是常规流,因为 默认流中的命令可以与非默认流中的命令同时运行。有关此新功能的更详细说明,请参见

      CUDA 7 Streams Simplify Concurrency

      此功能可以通过附加的--default stream per-thread 编译选项轻松启用。

      在上面链接的页面中,可以找到 Mark Harris 编写的示例。在这里,我想恢复我在False dependency issue for the Fermi architecture 发布的示例。特别是,在下面的新示例中,虽然我正在创建 3 流,但我不再使用第一个流,而是采用了默认流。

      这是生成的时间线--default stream per-thread 编译选项:

      如您所见,默认流中的执行没有利用并发性。

      在另一边,这是使用--default stream per-thread 编译选项生成的时间线

      如您现在所见,默认流执行与其他两个流执行重叠。

      #include <iostream>
      
      #include "cuda_runtime.h"
      #include "device_launch_parameters.h"
      
      #include <stdio.h>
      
      #include "Utilities.cuh"
      
      using namespace std;
      
      #define NUM_THREADS 32
      #define NUM_BLOCKS 16
      #define NUM_STREAMS 3
      
      __global__ void kernel(const int *in, int *out, int N)
      {
          int start = blockIdx.x * blockDim.x + threadIdx.x;
          int end =  N;
          for (int i = start; i < end; i += blockDim.x * gridDim.x)
          {
              out[i] = in[i] * in[i];
          }
      }
      
      int main()
      {
          const int N = 6000000;
      
          // --- Host side input data allocation and initialization. Registering host memory as page-locked (required for asynch cudaMemcpyAsync).
          int *h_in = new int[N]; for(int i = 0; i < N; i++) h_in[i] = 5;
          gpuErrchk(cudaHostRegister(h_in, N * sizeof(int), cudaHostRegisterPortable));
      
          // --- Host side input data allocation and initialization. Registering host memory as page-locked (required for asynch cudaMemcpyAsync).
          int *h_out = new int[N]; for(int i = 0; i < N; i++) h_out[i] = 0;
          gpuErrchk(cudaHostRegister(h_out, N * sizeof(int), cudaHostRegisterPortable));
      
          // --- Host side check results vector allocation and initialization
          int *h_checkResults = new int[N]; for(int i = 0; i < N; i++) h_checkResults[i] = h_in[i] * h_in[i];
      
          // --- Device side input data allocation.
          int *d_in = 0;              gpuErrchk(cudaMalloc((void **)&d_in, N * sizeof(int)));
      
          // --- Device side output data allocation. 
          int *d_out = 0;             gpuErrchk( cudaMalloc((void **)&d_out, N * sizeof(int)));
      
          int streamSize = N / NUM_STREAMS;
          size_t streamMemSize = N * sizeof(int) / NUM_STREAMS;
      
          // --- Set kernel launch configuration
          dim3 nThreads       = dim3(NUM_THREADS,1,1);
          dim3 nBlocks        = dim3(NUM_BLOCKS, 1,1);
          dim3 subKernelBlock = dim3((int)ceil((float)nBlocks.x / 2));
      
          // --- Create CUDA streams
          cudaStream_t streams[NUM_STREAMS];
          for(int i = 0; i < NUM_STREAMS; i++)
              gpuErrchk(cudaStreamCreate(&streams[i]));
      
          /**************************/
          /* BREADTH-FIRST APPROACH */
          /**************************/
      
          int offset = 0;
          cudaMemcpyAsync(&d_in[offset], &h_in[offset], streamMemSize, cudaMemcpyHostToDevice,     0);
          for(int i = 1; i < NUM_STREAMS; i++) {
              int offset = i * streamSize;
              cudaMemcpyAsync(&d_in[offset], &h_in[offset], streamMemSize, cudaMemcpyHostToDevice,     streams[i]);
          }
      
          kernel<<<subKernelBlock, nThreads>>>(&d_in[offset], &d_out[offset],   streamSize/2);
          kernel<<<subKernelBlock, nThreads>>>(&d_in[offset + streamSize/2],    &d_out[offset +  streamSize/2], streamSize/2);
      
          for(int i = 1; i < NUM_STREAMS; i++)
          {
              int offset = i * streamSize;
              kernel<<<subKernelBlock, nThreads, 0, streams[i]>>>(&d_in[offset], &d_out[offset],   streamSize/2);
              kernel<<<subKernelBlock, nThreads, 0, streams[i]>>>(&d_in[offset + streamSize/2],    &d_out[offset +  streamSize/2], streamSize/2);
          }
      
          for(int i = 1; i < NUM_STREAMS; i++) {
              int offset = i * streamSize;
              cudaMemcpyAsync(&h_out[offset], &d_out[offset], streamMemSize, cudaMemcpyDeviceToHost,   streams[i]);
          }
      
          cudaMemcpyAsync(&h_out[offset], &d_out[offset], streamMemSize, cudaMemcpyDeviceToHost,   0);
          for(int i = 1; i < NUM_STREAMS; i++) {
              int offset = i * streamSize;
              cudaMemcpyAsync(&h_out[offset], &d_out[offset], streamMemSize, cudaMemcpyDeviceToHost,   0);
          }
      
          for(int i = 0; i < NUM_STREAMS; i++)
              gpuErrchk(cudaStreamSynchronize(streams[i]));
      
          gpuErrchk(cudaDeviceSynchronize());
      
          // --- Release resources
          gpuErrchk(cudaHostUnregister(h_in));
          gpuErrchk(cudaHostUnregister(h_out));
          gpuErrchk(cudaFree(d_in));
          gpuErrchk(cudaFree(d_out));
      
          for(int i = 0; i < NUM_STREAMS; i++)
              gpuErrchk(cudaStreamDestroy(streams[i]));
      
          cudaDeviceReset();  
      
          // --- GPU output check
          int sum = 0;
          for(int i = 0; i < N; i++)      
              sum += h_checkResults[i] - h_out[i];
      
          cout << "Error between CPU and GPU: " << sum << endl;
      
          delete[] h_in;
          delete[] h_out;
          delete[] h_checkResults;
      
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-29
        • 2016-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-02
        • 2019-12-30
        相关资源
        最近更新 更多