5

我已经开始学习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);

再次复制CPU

cudaMemcpy(B, dev_B, Nel*Nface*sizeof(int),cudaMemcpyDeviceToHost);
  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; 
        }
    }
    

非常奇怪的是,将 dev_B 复制到 B 的时间与 j 索引的迭代次数成正比。

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

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

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

此外,我希望从 CPU 复制相同矩阵的时间将具有相同的顺序。

你知道有什么问题吗?

4

2 回答 2

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

编辑:附加信息:

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

于 2012-11-12T15:01:49.140 回答
1

至于你的第二个问题

 B[ind(tid,1,Nel)]=j// j in most cases do no go all the way to the Nel reach

在 GPU 上执行计算时,由于同步的原因,每个完成工作的线程都不会执行任何计算,直到同一个工作组中的所有线程都完成。

换句话说,您需要执行此计算的时间将是最坏情况下的时间,如果大多数线程没有一路下降也没关系。

我不确定你的第一个问题,你如何测量时间?我对 cuda 不太熟悉,但我认为当从 CPU 复制到 GPU 时,实现会缓冲您的数据,隐藏所涉及的有效时间。

于 2012-11-12T09:52:53.603 回答