如何正确测量CUDA时间?

时间:2012-08-15 13:17:37

标签: c performance algorithm cuda measurement

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

假设我们有以下代码:

    //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<<<dimB, dimT>>>(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();
}

3 个答案:

答案 0 :(得分:2)

您使用了错误的测量功能。 clock衡量您的流程花在CPU上的时间,而不是挂钟时间。

答案 1 :(得分:1)

看看High Precision Timer lib,它使用OS相关的计时功能来测量时间。

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

如果您使用的是Windows,则应使用QueryPerformanceFrequencyQueryPerformanceCounter 在Linux上:gettimeofday()

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

答案 2 :(得分:0)

一些想法:

  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引擎的特斯拉装置上,这甚至更好。

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

  6. 在GPU上运行多个线程以进行公平比较。

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