如何正确测量CUDA时间?

我试图正确测量并行和顺序执行的时间,但我怀疑是因为:

假设我们有以下代码:

//get the time clock_t start,finish; double totaltime; start = clock(); double *d_A, *d_B, *d_X; cudaMalloc((void**)&d_A, sizeof(double) * Width * Width); cudaMalloc((void**)&d_B, sizeof(double) * Width); cudaMalloc((void**)&d_X, sizeof(double) * Width); cudaMemcpy(d_A, A, sizeof(double) * Width * Width, cudaMemcpyHostToDevice); cudaMemcpy(d_B, B, sizeof(double) * Width, cudaMemcpyHostToDevice); do_parallel_matmul<<>>(d_A, d_B, d_X, Width); cudaMemcpy(X, d_X, sizeof(double) * Width, cudaMemcpyDeviceToHost); finish = clock(); totaltime=(double)(finish-start)/CLOCKS_PER_SEC; printf("%f", totaltime); 

此时间比连续测量的时间长得多,如下所示:

 clock_t start,finish; double totaltime; start = clock(); do_seq_matmult(); finish = clock(); totaltime=(double)(finish-start)/CLOCKS_PER_SEC; printf("%f", totaltime); 

所以我不知道我是否应该只测量CUDA内核时间,如下所示:

 clock_t start,finish; double totaltime; start = clock(); do_parallel_matmul(); finish = clock(); totaltime=(double)(finish-start)/CLOCKS_PER_SEC; printf("%f", totaltime); 

并避免主机和设备之间的内存复制……

我问上面因为我要在并行执行和顺序执行之间提交一个比较……但是如果我在CUDA中测量内存副本,那么CUDA和C之间没有很大的区别……

编辑:

 void do_seq_matmult(const double *A, const double *X, double *resul, const int tam) { *resul = 0; for(int i = 0; i < tam; i++) { for(int j = 0; j < tam; j++) { if(i != j) *resul += A[i * tam + j] * X[j]; } } } __global__ void do_parallel_matmul( double * mat_A, double * vec, double * rst, int dim) { int rowIdx = threadIdx.x + blockIdx.x * blockDim.x; // Get the row Index int aIdx; while( rowIdx < dim) { rst[rowIdx] = 0; // clean the value at first for (int i = 0; i < dim; i++) { aIdx = rowIdx * dim + i; // Get the index for the element a_{rowIdx, i} rst[rowIdx] += (mat_A[aIdx] * vec[i] ); // do the multiplication } rowIdx += gridDim.x * blockDim.x; } __syncthreads(); } 

一些想法:

  1. 在没有主机分配内存的情况下,分配设备内存并将其与CPU进行比较是不公平的。

  2. 如果cudaMalloc((void**)&d_A, sizeof(double) * Width * Width); 是第一个CUDA调用它将包括CUDA上下文创建,这可能是一个重大的开销。

  3. 时间cudamemcpy不是一个公平的CPU / GPU比较,因为这个时间将取决于系统的PCI-e带宽。 另一方面,如果从CPU的角度看内核为加速,则需要包含memcpy。 为了达到峰值PCI-e带宽,请使用页锁定内存。

  4. 如果您的应用程序要运行乘法几次,则可以通过将副本与内核执行重叠来隐藏大部分memcpy。 在具有双DMA引擎的Tesla装置上,这甚至更好。

  5. 定时内核本身需要您在停止计时器之前将CPU与GPU同步,否则您将只计时内核启动而不执行。 从CPU调用内核是异步的。 如果你想在GPU上执行内核,请使用cudaEvents。

  6. 在GPU上运行许multithreading以获得公平的比较。

  7. 改进内核,你可以做得更好。

您使用错误的function进行测量。 clock测量您的进程花费在CPU上的时间而不是挂钟时间。

看看高精度定时器 lib,它使用OS相关的定时function来测量时间。

它使用一组function,可以提供微秒精度

如果你在Windows上,你应该在Linux上使用QueryPerformanceFrequencyQueryPerformanceCountergettimeofday()

它非常轻便易用。 适用于Windows和Linux。