2016-12-05 6 views
0

私の実行時プログラムでは、cpuとgpuは非同期的には計算できますが、協力的に計算するのはなぜですか?私の実行時プログラムでは、cpuとgpuは非同期的に計算できますが、協調的にはなぜですか?

私はプログラムの時間を測定して、合計時間はCPUの計算時間とGPUの計算時間の合計時間です。視覚的なプロファイルを通して、CPUが完了するまでGPUが計算しないことがわかります。私の目的は、CPUがgpuと同じ時間に計算することです。

プラットフォーム: ウィンドウ10
CUDA 7.5
vs2013

デバッグモードでコンパイルされたコード(NO最適化)

#include "cuda_runtime.h" 
#include "device_launch_parameters.h" 
#include <stdio.h> 
#include<time.h> 
__global__ void addKernel() 
{ 
    int a ; 
    for (int i = 0; i < 10000;i++) 
    for (int j = 0; j < 10000;j++) 
     a = i; 
} 
void comput() 
{ 
    int a = 1; 
    for (int i = 0; i < 10000;i++) 
     for (int j = 0; j < 10000; j++) 
     { 
      for (int k = 0; k < 100;k++) 
       a = j; 

     } 

} 

int main() 
{ 
    cudaSetDevice(0); 
    cudaEvent_t start, stop1; 
    cudaEventCreate(&start); 
    cudaEventCreate(&stop1); 

    clock_t ss = clock(); 
    cudaEventRecord(start,0); 
    addKernel<<<1,64>>>(); 
    cudaEventRecord(stop1,0); 

    clock_t ct = clock(); 
    comput(); 
    clock_t ctt = clock(); 

    cudaEventSynchronize(stop1); 
    cudaDeviceSynchronize(); 
    clock_t sss = clock(); 

    float t1; 
    cudaEventElapsedTime(&t1, start, stop1); 
    printf("clock GPU :%.4f s\n", t1/1000); 
    printf("clock cpu:%f s\n",(float) (ctt - ct)/CLOCKS_PER_SEC); 
    printf("clock total time: %f s\n", (float)(sss - ss)/CLOCKS_PER_SEC); 

    cudaEventDestroy(start); 
    cudaEventDestroy(stop1); 
    cudaDeviceReset(); 

} 

答えて

1

cuda programming guideより:

プログラマグローバルに無効非同期缶実行中のすべてのCUDAアプリケーションのカーネル起動CUDA_LAUNCH_BLOCKING環境変数を1に設定することで、システム上でこの機能を使用することができます。この機能は、デバッグ目的でのみ提供されるため、本番ソフトウェアを確実に実行させる方法として使用しないでください。

同時カーネルプロファイリングが有効になっていない限り、ハードウェアカウンターがプロファイラー(Nsight、Visual Profiler)によって収集されると、カーネルの起動が同期します。非同期メモリのコピーは、ページロックされていないホストメモリを含む場合にも同期します。

また、最適化がない場合、ホスト機能は非常に長い時間、おそらくカーネルの何百万回も実行されます。最適化を行うと、実際には何も実行されずすぐに戻ります。

実行時間をテストするために、それぞれCUDA_LAUNCH_BLOCKING=1CUDA_LAUNCH_BLOCKING=0のバイナリを実行することをお勧めします。また、カーネルとホスト機能を意味のあるものに変更してください。

1

遊んでいる問題(潜在的に)のカップルがここにあります

  • あなたはWDDMドライバを使用している場合(TCCドライバではなく)、カーネルの起動がの影響を低減するために、最大バッチ処理されますWDDMドライバーのより高い打ち上げオーバヘッド。これは、ドライバがcudaEventSynchronize()コールに遭遇するまで、より多くの仕事を待つaddKernel()の打ち出しを延期することを意味します.¹⁾しかし、今回はcomput()がすでに終了しています。

    だからあなたの例のCPUとGPUの仕事で実際に並列で実行していない、しかし、GPU上のaddKernel()は、実際にCPUにcomput()後を実行します。
    comput()に電話をかける前に、バッチ処理を防止して、をinserting a call to cudaStreamQuery(0)で強制的に起動することができます。

  • addKernel()およびcompute()は、外部からの影響を受けず(ローカル変数aのみを設定します)、コンパイラによって完全に最適化されている可能性があります。デバッグモードでコンパイルすると、これらの最適化がすべて妨げられることはありません。これにより、カーネルの起動とタイミングのオーバーヘッドを測定するだけで、非同期実行を実証することが難しくなります。
    したがって、実際の作業を実行するコード(ベクトルの合計など)を置き換え、その結果をグローバル変数に格納します。

  • 彼の答えで指摘されているように、プロファイラは特定の条件下で同期してカーネルを起動することがあります。


¹⁾それ以上の作業はしばらくまで来ない場合は、待ち時間もアウト時間とaddKernel()cudaEventSynchronize()コールの前に立ち上げたことがあります可能性があります。

+1

これはドライバの問題です。私はcomput()を呼び出す前にcudaEventQuery(stop1)を呼び出して問題を解決しました。ありがとうございました。 – ZhangJiwei

+0

はい、 'cudaEventQuery()'は現在のバッチをすぐに起動するのと同じプロパティを持ちます。これはあなたの問題を解決してうれしいです。 – tera

関連する問題