从GPU复制到CPU比将CPU复制到GPU要慢

gio*_*rgk 5 c++ cuda gpu

我已经开始学习cuda一段时间了,我有以下问题

看看我在下面的做法:

复制GPU

int* B;
// ...
int *dev_B;    
//initialize B=0

cudaMalloc((void**)&dev_B, Nel*Nface*sizeof(int));
cudaMemcpy(dev_B, B, Nel*Nface*sizeof(int),cudaMemcpyHostToDevice);
//...

//Execute on GPU the following function which is supposed to fill in 
//the dev_B matrix with integers


findNeiborElem <<< Nblocks, Nthreads >>>(dev_B, dev_MSH, dev_Nel, dev_Npel, dev_Nface, dev_FC);
Run Code Online (Sandbox Code Playgroud)

再次复制CPU

cudaMemcpy(B, dev_B, Nel*Nface*sizeof(int),cudaMemcpyDeviceToHost);
Run Code Online (Sandbox Code Playgroud)
  1. 将数组B复制到dev_B只需要几分之一秒.但是将数组dev_B复制回B需要永远.
  2. findNeiborElem函数涉及每个线程的循环,例如它看起来像这样

    __ global __ void findNeiborElem(int *dev_B, int *dev_MSH, int *dev_Nel, int *dev_Npel, int *dev_Nface, int *dev_FC){
    
        int tid=threadIdx.x + blockIdx.x * blockDim.x;
        while (tid<dev_Nel[0]){
            for (int j=1;j<=Nel;j++){
                 // do some calculations
                 B[ind(tid,1,Nel)]=j// j in most cases do no go all the way to the Nel reach
                 break; 
            }
        tid += blockDim.x * gridDim.x; 
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

对它来说非常奇怪的是,将dev_B复制到B的时间与j index的迭代次数成正比.

例如,如果Nel=5那时时间是大约5 sec.

当我增加Nel=20时间约20 sec.

我希望复制时间应该独立于分配Matrix值的内部迭代dev_B.

此外,我希望从CPU复制相同矩阵的时间也是相同的顺序.

你知道什么是错的吗?

dre*_*ash 3

您应该使用事件,而不是使用clock()来测量时间:

对于事件,你会得到这样的东西:

  cudaEvent_t start, stop;   // variables that holds 2 events 
  float time;                // Variable that will hold the time
  cudaEventCreate(&start);   // creating the event 1
  cudaEventCreate(&stop);    // creating the event 2
  cudaEventRecord(start, 0); // start measuring  the time

  // What you want to measure
  cudaMalloc((void**)&dev_B, Nel*Nface*sizeof(int));
  cudaMemcpy(dev_B, B, Nel*Nface*sizeof(int),cudaMemcpyHostToDevice);

  cudaEventRecord(stop, 0);                  // Stop time measuring
  cudaEventSynchronize(stop);               // Wait until the completion of all device 
                                            // work preceding the most recent call to cudaEventRecord()

  cudaEventElapsedTime(&time, start, stop); // Saving the time measured
Run Code Online (Sandbox Code Playgroud)

编辑:附加信息:

“内核启动在完成之前将控制权返回给 CPU 线程。因此,您的计时构造正在测量内核执行时间以及第二个 memcpy。当在内核之后计时复制时,您的计时器代码将立即执行,但是cudaMemcpy 在启动之前等待内核完成。这也解释了为什么数据返回的计时测量似乎根据内核循环迭代而变化。它还解释了为什么在内核函数上花费的时间“可以忽略不计”。归功于罗伯特·克罗维拉

  • 是的,你应该使用这个方法。内核启动*在完成之前*将控制权返回给 CPU 线程。因此,您的计时构造正在测量内核执行时间以及第二个 memcpy。当在内核之后计时复制时,您的计时器代码将立即执行,但 cudaMemcpy 在启动之前等待内核完成。这也解释了为什么数据返回的计时测量似乎根据内核循环迭代而变化。它还解释了为什么花在内核函数上的时间“可以忽略不计”。 (5认同)