2015-12-18 51 views
4

在定義瞭如何處理錯誤:正確處理大於GPU可用內存的結果數組?

static void HandleError(cudaError_t err, 
         const char *file, 
         int line) { 
    if (err != cudaSuccess) { 
     printf("%s in %s at line %d\n", cudaGetErrorString(err), 
       file, line); 
     exit(EXIT_FAILURE); 
    } 
} 
#define HANDLE_ERROR(err) (HandleError(err, __FILE__, __LINE__)) 

通常情況下,存儲在陣列d_results我們的結果,double類型,大小爲N,可在GPU內存在一次分配中,我們可以管理將數據從設備傳輸到主機,如下所示:

double *d_results; 
    HANDLE_ERROR(cudaMalloc(&d_results,N*sizeof(double))); 
//Launch our kernel to do some computations and store the results in d_results 
..... 
// and transfer our data from the device to the host 
vector<double> results(N); 
cudaMemcpy(results.data(),d_results,N*sizeof(double),cudaMemcpyDeviceToHost); 

如果第二行因爲沒有足夠的內存一次存儲所有結果而失敗。我如何設法進行計算並將結果正確傳輸到主機?是否必須按批次進行計算?我寧願避免手動配料。在CUDA中管理這種情況的標準方法是什麼?

+0

手動配料可能是最好的選擇。唯一的其他常規選項是在CUDA中使用主機映射內存,也稱爲零拷貝內存。這允許主機內存直接映射到GPU的內存空間,並像GPU全局內存那樣訪問。但是對於通用訪問來說,它通常很慢。 –

回答

2

配料是最好的選擇。

#include <assert.h> 
#include <iostream> 

int main() 
{ 
    // Allocate 4 Gb array on host 
    const size_t N = 1 << 30; 
    int * data = new int[N]; 

    // Allocate as much memory as will fit on GPU 
    size_t total_mem, free_mem; 
    cudaMemGetInfo(&free_mem, &total_mem); 
    const size_t MB = 1 << 20; 

    cudaError_t status; 
    int *buffer; 
    size_t buffer_size = free_mem; 
    for(; buffer_size > MB; buffer_size -= MB) { 
     status = cudaMalloc((void **)&buffer, buffer_size); 
     if (status == cudaSuccess) 
      break; 
    } 

    std::cout << "Allocated " << buffer_size << " bytes on GPU" << std::endl; 

    // Loop through host source data in batches 
    std::cout << N << " items require processing" << std::endl; 
    size_t batchN = buffer_size/sizeof(int); 
    size_t remainN = N; 
    int * dp = data; 
    std::cout << "Using batch size " << batchN << std::endl; 

    for(; remainN > 0; remainN -= batchN) { 
     batchN = (remainN < batchN) ? remainN : batchN; 
     size_t worksize = batchN * sizeof(int); 
     std::cout << "Processing batch of size " << batchN; 
     std::cout << "," << remainN << " items remaining" << std::endl; 
     cudaMemcpy(buffer, dp, worksize, cudaMemcpyHostToDevice); 
     cudaMemset(buffer, 0xff, worksize); 
     cudaMemcpy(dp, buffer, worksize, cudaMemcpyDeviceToHost); 
     dp += batchN; 
    } 

    for(size_t i = 0; i < N; i++) { 
     assert(data[i] == 0xffffffff); 
    } 

    cudaDeviceReset(); 

    return 0; 
} 

這基本上是

  1. 分配儘可能多的可用內存爲您的設備有
  2. 迭代處理輸入數據到:如果你做這樣的事情,你可以自動大部分的配料過程GPU在緩衝區大小塊直到一切都完成

在上面的代碼中,我用cudaMemset作爲真實內核的代理,但它讓你瞭解什麼是必須的。如果你想更有趣,你可以使用兩個緩衝區和流(與註冊/固定主機內存)並異步複製,以獲得計算/副本重疊,這將改善非平凡情況下的整體性能。

相關問題