2

並列実行と順次実行の時間を正しく測定しようとしていますが、次の理由で疑問があります。

次のコードがあるとします。

    //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();
}
4

3 に答える 3

2

測定に間違った関数を使用しています。clockウォールクロック時間ではなく、プロセスがCPUに費やした時間を測定します。

于 2012-08-15T14:47:52.830 に答える
1

High Precision Timer libを見てください。これは、OS関連のタイミング関数を使用して時間を測定します。

マイクロ秒の精度を提供できる一連の関数を使用します。

QueryPerformanceFrequencyWindowsを使用している場合はQueryPerformanceCounter 、Linuxを使用する必要があります。gettimeofday()

とても軽くて使いやすいです。WindowsとLinuxで利用できます。

于 2012-08-15T14:53:57.047 に答える
0

いくつかの考え:

  1. デバイスメモリの割り当てのタイミングを計り、ホストにメモリを割り当てずにCPUと比較することは公平ではありません。

  2. が最初のCUDA呼び出しである場合 cudaMalloc((void**)&d_A, sizeof(double) * Width * Width); 、CUDAコンテキストの作成が含まれるため、かなりのオーバーヘッドが発生する可能性があります。

  3. タイミングcudamemcpyは、CPU / GPUの公平な比較ではありません。これは、この時間がシステムのPCI-e帯域幅に依存するためです。一方、CPUの観点からカーネルをアクセラレーションと見なす場合は、memcpyを含める必要があります。PCI-e帯域幅をピークにするには、ページロックメモリを使用します。

  4. アプリケーションが乗算を数回実行する場合は、コピーとカーネルの実行をオーバーラップさせることで、ほとんどのmemcpyを非表示にすることができます。これは、デュアルDMAエンジンを搭載しているTeslaユニットではさらに優れています。

  5. カーネル自体のタイミングを調整するには、タイマーを停止する前にCPUをGPUと同期させる必要があります。そうしないと、カーネルの起動のみを計測し、実行は計測しません。CPUからのカーネルの呼び出しは非同期です。GPUでのカーネル実行の時間を計りたい場合は、cudaEventsを使用してください。

  6. 公正な比較を得るために、GPUで多くのスレッドを実行します。

  7. カーネルを改善してください、あなたはより良くすることができます。

于 2012-08-15T14:52:54.730 に答える