2011-11-29 146 views
1

我在嘗試編寫CUDA程序時遇到困難。我有一個大約524k浮點值(1.0)的數組,我使用縮減技術來添加所有的值。如果我只想運行一次,問題就可以正常工作,但我真的想多次運行內核,以便最終總結超過10億個值。CUDA - 多次調用內核

我以524k爲單位做這件事的原因是當我在GPU上超過100萬時,我總是得到零。這應該不會超過卡上的內存,但在這一點上總是失敗。

無論如何,當我循環內核只有一次,一切工作正常。也就是說,沒有循環是好的。當我用循環運行時,它返回零。我懷疑我會走出一些地方,但我無法弄清楚。這讓我瘋狂。

任何幫助表示讚賞,

感謝,

下面是代碼:

#include <stdio.h> 
#include <stdlib.h> 
#include "cutil.h" 

#define TILE_WIDTH  512 
#define WIDTH   524288 
//#define WIDTH   1048576 
#define MAX_WIDTH  524288 

#define BLOCKS   WIDTH/TILE_WIDTH 

__global__ void PartSum(float * V_d) 
{ 
    int tx = threadIdx.x; 
    int bx = blockIdx.x; 

    __shared__ float partialSum[TILE_WIDTH]; 

    for(int i = 0; i < WIDTH/TILE_WIDTH; ++i) 
    { 
     partialSum[tx] = V_d[bx * TILE_WIDTH + tx]; 
     __syncthreads(); 


     for(unsigned int stride = 1; stride < blockDim.x; stride *= 2) 
     { 
     __syncthreads(); 
     if(tx % (2 * stride) == 0) 
      partialSum[tx] += partialSum[tx + stride]; 
     } 
    } 

    if(tx % TILE_WIDTH == 0) 
     V_d[bx * TILE_WIDTH + tx] = partialSum[tx]; 
} 

int main(int argc, char * argv[]) 
{ 
    float * V_d; 
    float * V_h; 
    float * R_h; 
    float * Result; 
    float * ptr; 

    dim3 dimBlock(TILE_WIDTH,1,1); 
    dim3 dimGrid(BLOCKS,1,1); 

    // Allocate memory on Host 
    if((V_h = (float *)malloc(sizeof(float) * WIDTH)) == NULL) 
    { 
     printf("Error allocating memory on host\n"); 
     exit(-1); 
    } 

    if((R_h = (float *)malloc(sizeof(float) * MAX_WIDTH)) == NULL) 
    { 
     printf("Error allocating memory on host\n"); 
     exit(-1); 
    } 

    // If MAX_WIDTH is not a multiple of WIDTH, this won't work 
    if(WIDTH % MAX_WIDTH != 0) 
    { 
     printf("The width of the vector must be a multiple of the maximum width\n"); 
     exit(-3); 
    } 

    // Initialize memory on host with 1.0f 
    ptr = V_h; 
    for(long long i = 0; i < WIDTH; ++i) 
    { 
     *ptr = 1.0f; 
     ptr = &ptr[1]; 
    } 

    ptr = V_h; 

    // Allocate memory on device in global memory 
    cudaMalloc((void**) &V_d, MAX_WIDTH*(sizeof(float))); 
    float Pvalue = 0.0f; 
    for(int i = 0; i < WIDTH/MAX_WIDTH; ++i) 
    { 


    if((Result = (float *) malloc(sizeof(float) * WIDTH)) == NULL) 
    { 
     printf("Error allocating memory on host\n"); 
     exit(-4); 
    } 

    for(int j = 0; j < MAX_WIDTH; ++j) 
    { 
     Result[j] = *ptr; 
     ptr = &ptr[1]; 
    } 

     ptr = &V_h[i*MAX_WIDTH]; 
     // Copy portion of data to device 
     cudaMemcpy(V_d, Result, MAX_WIDTH*(sizeof(float)), cudaMemcpyHostToDevice); 

     // Execute Kernel 
     PartSum<<<dimGrid, dimBlock>>>(V_d); 

     // Copy data back down to host 
     cudaMemcpy(R_h, V_d, MAX_WIDTH*(sizeof(float)), cudaMemcpyDeviceToHost); 

     for(int i = 0; i < MAX_WIDTH; i += TILE_WIDTH) 
     { 
     Pvalue += R_h[i]; 
     } 
printf("Pvalue == %f\n", Pvalue); 

    free(Result); 


    } 

// printf("WIDTH == %d items\n", WIDTH); 
// printf("Value: %f\n", Pvalue); 

    cudaFree(V_d); 
    free(V_h); 
    free(R_h); 
    return(1); 
} 

好吧,我想我已經縮小到與問題V_d在設備上。我懷疑我已經超出了陣列的範圍了。如果我分配了實際需要的內存量的2倍,程序將以預期的結果完成。問題是,我無法弄清楚造成問題的原因。

+0

你有使用cudaMemcpyDeviceToHost的特殊原因嗎?既然你想要更多的內核迭代,你可以考慮使用'cudaMemcpyDeviceToDevice'來代替。 – karlphillip

+0

我不相信你真的需要CUDA - 這將會是I/O的主導因素,因爲你只需要每點添加一個操作 - 你也可以使用CPU。你有沒有對這個實現的CPU實現進行基準測試?你認爲CUDA的實現可能會快多少,因爲它全部是數據移動,幾乎沒有計算? –

+0

這對我來說是一個學習實驗。我意識到這並不高效。 –

回答

2

我覺得我看到的第一個錯誤的位置:

if(tx % TILE_WIDTH == 0) 
     V_d[bx * TILE_WIDTH + tx] = partialSum[tx]; 

範圍TX是0-511,它從來沒有達到512所以如果條件永遠不會真正。如果(tx%(TILE_WIDTH-1)== 0),可以將其寫爲

+0

啊!我沒有看到!謝謝。 –

2

首先,感謝大家給了這個看看和任何幫助。

其次,我終於弄清楚我做錯了什麼。 BLOCKS應該被定義爲MAX_WIDTH/TILE_WIDTH,而不是WIDTH/TILE_WIDTH。我的部分愚蠢愚蠢的錯誤。

再次感謝。