2013-11-25 28 views
0

我有一個由多個CPU線程組成的應用程序,每個CPU線程在我的GPU上的相同cudaContext中創建一個單獨的cudaStream。我有一臺特斯拉K20c。我使用Windows 7 64位和Cuda 5.5。多線程CPU CUDA應用程序在調用CudaFree時不會異步

這裏是我的代碼:

#include "gpuCode.cuh" 

__global__ void kernelAddConstant1(int *g_a, const int b) 
{ 
    int idx = blockIdx.x * blockDim.x + threadIdx.x; 
    g_a[idx] += b; 
    for (int i = 0; i < 4000000.0; i++) 
    { 
     if (i%2 == 0) 
     { 
      g_a[idx] += 5; 
     } 
     else 
     { 
      g_a[idx] -= 5; 
     } 
    } 
} 


// a predicate that checks whether each array elemen is set to its index plus b 
int correctResult(int *data, const int n, const int b) 
{ 
    for (int i = 0; i < n; i++) 
    { 
     if (data[i] != i + b) 
     { 
      return 0; 
     } 
    } 
    return 11; 
} 

int gpuDo() 
{ 
    cudaSetDevice(0); 
    cudaStream_t stream; 
    cudaStreamCreate(&stream); 

    int *a; 
    int *d_a; 

    unsigned int n; 
    unsigned int nbytes; 

    int b; 

    n = 2 * 8192/16; 
    nbytes = n * sizeof(int); 
    b = 7;  // value by which the array is incremented 

    cudaHostAlloc((void**)&a, nbytes, cudaHostAllocDefault) ; 
    cudaMalloc((void **)&d_a, nbytes); 

    for (unsigned int i = 0; i < n; i++) 
     a[i] = i; 

    unsigned int nbytes_per_kernel = nbytes; 
    dim3 gpu_threads(128); // 128 threads per block 
    dim3 gpu_blocks(n/gpu_threads.x); 

    cudaMemsetAsync(d_a, 0, nbytes_per_kernel, stream); 

    cudaMemcpyAsync(d_a, a, nbytes_per_kernel, cudaMemcpyHostToDevice, stream); 


    kernelAddConstant1<<<gpu_blocks, gpu_threads, 0, stream>>>(d_a, b); 

    cudaMemcpyAsync(a, d_a, nbytes_per_kernel, cudaMemcpyDeviceToHost, stream); 
    cudaStreamSynchronize (stream) ; 
    cudaStreamDestroy(stream); 

    //cudaFree(d_a); 

    int bResult = correctResult(a, n, b); 

    //if (a) 
     //cudaFreeHost(a); // free CPU memory 

    return bResult; 
} 

void gpuEnd() 
{ 
    cudaDeviceReset(); 
} 

當我離開cudaFree和cudaFreeHost註釋掉我實現以下目的:

nVidia Visual Profiler Async nVidia Visual Profiler Async bottom

這是除了我有一個內存完美泄漏,因爲我沒有使用cudaFree和cudaFreeHost。當我使用cudaFree和cudaFreeHost我得到以下結果:

nVidia Visual Profiler sync top nvidia visual Profiler sync bottom

這是不好的。當使用cudaFree時,一些流等待其他流首先完成,一些流異步工作。我假設這是因爲cudaFree不是異步的,但這並不能解釋爲什麼它有時會像在前三個內核中那樣工作,但在其他時間沒有。如果cudaFree被調用,但GPU已經在忙着做其他事情,可以讓CPU繼續計算,並讓cudaFree自動獲得第一次機會?是否有另一種方法來解決這個問題?謝謝你提供的所有幫助!

回答

1

是的,cudaFree不是異步的。 Niether是cudaMalloc

在定時關鍵代碼之前先做好所有的分配,並在最後執行免費操作。

這對你來說應該特別容易,因爲分配的大小每次都是一樣的。

相同的註釋適用於流創建。我不打擾他們創造和摧毀他們。創造無論你想要多少,並重復使用,直到你完成。