2012-07-14 106 views
2

我正在研究一个简单的cuda程序,我发现90%的时间来自单个语句,这个语句是从设备到主机的cudamemcpy。该程序在600-700微秒内将一些2MB数据从主机传输到设备,并在10ms内将4MB数据从设备复制回主机。我的程序花费的总时间是13ms。我的问题是,为什么在从设备到主机和主机到设备的两次复制中存在不对称性。是否因为cuda devlopers认为复制回来通常会以字节为单位。我的第二个问题是有什么办法可以绕过它。CUDA主机到设备的传输速度比设备到主机的传输速度更快

我使用的是具有343核心和1GB内存的Fermi GTX560显卡。

+2

这是最有可能的时间神器不是真实的。内核启动是异步的,所以很可能,设备 - 主机传输的10ms包括内核执行时间。 – talonmies 2012-07-14 19:33:28

+0

我不这么认为。我使用rdtsc这是一个硬件计数器,并且我已经在cudaMemcpy(...);之上和之下放置了两个反标签。此外,为了防止噪音进入系统,我一再重复实验。内核启动是异步的,但我没有使用cudaMemcpyAsync。并且在内核调用结束之前它不能被执行。 – 2012-07-14 19:46:14

+3

尝试在设备托管副本之前放置cudaDeviceSynchronize()调用。我预测为cudaMemcpy调用测量的时间将大大减少。 – talonmies 2012-07-14 19:52:48

回答

2

CUDA功能的定时与CPU有点不同。首先,请确保在应用程序启动时不要考虑CUDA的初始化成本,否则可能会在开始计时时初始化CUDA的初始化成本。

int main (int argc, char **argv) { 
    cudaFree(0); 
    ....//cuda is initialized.. 

} 

使用Cutil计时器这样

unsigned int timer; 
cutCreateTimer(&timer); 
cutStartTimer(timer); 

//your code, to assess elapsed time.. 

cutStopTimer(timer); 
printf("Elapsed: %.3f\n", cutGetTimerValue(timer)); 
cutDeleteTimer(timer); 

现在,这些预备步骤之后,让我们看看这个问题。当调用内核时,CPU部分将被暂停,直到调用被传递给GPU。当CPU继续运行时,GPU将继续执行。如果您调用cudaThreadSynchronize(..),则CPU将停止运行,直到GPU完成当前调用。 cudaMemCopy操作还要求GPU完成其执行,因为请求由内核填充的值。

kernel<<<numBlocks, threadPerBlock>>>(...); 

cudaError_t err = cudaThreadSynchronize(); 
if (cudaSuccess != err) { 
    fprintf(stderr, "cudaCheckError() failed at %s:%i : %s.\n", __FILE__, __LINE__, cudaGetErrorString(err)); 
    exit(1); 
} 

//now the kernel is complete.. 
cutStopTimer(timer); 

因此,在调用停止计时器功能之前进行同步。如果在内核调用之后放置内存副本,则内存复制的已用时间将包含内核执行的一部分内容。因此memCopy操作可能会在定时操作之后进行。

还有一些分析器计数器可用于评估内核的某些部分。

How to profile the number of global memory transactions for cuda kernels?

How Do You Profile & Optimize CUDA Kernels?