2016-04-05 48 views
1

下面的CUDA內核應該爲3D圖像添加圖像切片,即沿一維摺疊3D體積,並通過逐像素添加生成一個2D圖像。 image_in數據指針的大小爲128 * 128 * 128,它是使用函數GetOutputBuffer()從ITK :: Image獲得的。在閱讀ITK文檔後,我認爲我們可以安全地假設數據指針指向圖像數據的一段連續內存,沒有填充。 image_out只是一個尺寸爲128 * 128的2D圖像,也是由ITK :: Image生成的。爲了完整,我包含了關於圖像的信息,但問題更多的是關於CUDA原子,可能是非常基本的。該代碼首先計算線程ID並將該ID映射到128 * 128的範圍內,這意味着沿着我們執行的維度的同一行中的所有像素將具有相同的idx。然後使用這個idx,atomicAdd被用來更新image_out。CUDA atomicAdd失敗

__global__ void add_slices(int* image_in, int* image_out) { 
    int tid = threadIdx.x + blockIdx.x * blockDim.x; 
    int idx = tid % (128 * 128); 
    int temp = image_in[tid]; 

    atomicAdd(&image_out[idx], temp); 

} 

我初始化image_out是通過以下的方式,有兩種方法我用了類似的結果嘗試:

int* image_out = new int[128 * 128]; 
for (...) { 
    /* assign image_out to zeros */ 
} 

和一個使用ITK接口:

out_image->SetRegions(region2d); 
out_image->Allocate(); 
out_image->FillBuffer(0); 
// Obtain the data buffer 
int* image_out = out_image->GetOutputBuffer(); 

然後我設置CUDA爲:

unsigned int size_in = 128 * 128 * 128; 
unsigned int size_out = 128 * 128; 
int *dev_in; 
int *dev_out; 
cudaMalloc((void**)&dev_in, size_in * sizeof(int)); 
cudaMalloc((void**)&dev_out, size_out * sizeof(int)); 
cudaMemcpy(dev_in, image_in, size_in * sizeof(int), cudaMemcpyHostToDevice); 
add_slices<<<size_in/64, 64 >>>(dev_in, dev_out); 
cudaMemcpy(image_out, dev_out, size_out * sizeof(int), cudaMemcpyDeviceToHost); 

上述代碼有問題嗎?我在這裏尋求幫助的原因來自於上述代碼有時可能產生正確結果(每50次運行代碼一次,也許我發誓我已經看到至少兩次正確結果),而其餘的的時間只是產生了一些垃圾。問題是否來自atomicAdd()函數?在開始的時候我的圖像類型是雙,其中CUDA不支持atomicAdd(雙*雙),所以我使用Nvidia公司只是用於測試目的而提供的以下

__device__ double atomicAdd(double* address, double val) 
{ 
    unsigned long long int* address_as_ull = 
              (unsigned long long int*)address; 
    unsigned long long int old = *address_as_ull, assumed; 
    do { 
     assumed = old; 
     old = atomicCAS(address_as_ull, assumed, 
         __double_as_longlong(val + 
         __longlong_as_double(assumed))); 
    } while (assumed != old); 
    return __longlong_as_double(old); 
} 

然後代碼我交換我的全部圖像到int然後情況仍然是相同的,大部分時間garbages而一旦在藍色月亮正確的結果。

我需要打開一些編譯標誌嗎?我正在使用CMAKE構建項目使用

find_package(CUDA QUIET REQUIRED) 

爲CUDA支持。以下是我設置CUDA_NVCC_FLAGS的方式

set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -arch=sm_30"), 

也許我錯過了什麼?

任何建議將不勝感激,我會更新問題,如果需要更多的代碼信息。

+0

你是否在調用內核之前在某處初始化'image_out'? – talonmies

+0

@talonmies感謝您的回覆!是的,我使用ITK庫函數image_out-> Allocate()和image_out-> FillBuffer(0)來初始化圖像。我也只是簡單地傳遞一個普通的初始化C++ new()ed數組,結果是一樣的。 –

+0

您能否將最簡單的完整示例編輯成您的問題?您不能將C++新分配的指針傳遞給CUDA內核。如果你這樣做,這個問題有*無關*與atomicAdd – talonmies

回答

2

所以事實證明,解決這個問題的方法是添加以下行來初始化dev_out指向的內存。

cudaMemcpy(dev_out, image_out, size_out * sizeof(int), cudaMemcpyHostToDevice); 

我忘了初始化它,因爲我在想,這是一個輸出變量,我初始化它的主機上。

就像talonmies說的那樣,它跟atomicAdd完全沒有關係。 atomicAdd和int的版本都是完美的。只記得在設備上初始化你的變量。

+0

感謝您添加答案,這有助於所有人,包括未來的訪問者提供類似的問題。 – talonmies