下面的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"),
也許我錯過了什麼?
任何建議將不勝感激,我會更新問題,如果需要更多的代碼信息。
你是否在調用內核之前在某處初始化'image_out'? – talonmies
@talonmies感謝您的回覆!是的,我使用ITK庫函數image_out-> Allocate()和image_out-> FillBuffer(0)來初始化圖像。我也只是簡單地傳遞一個普通的初始化C++ new()ed數組,結果是一樣的。 –
您能否將最簡單的完整示例編輯成您的問題?您不能將C++新分配的指針傳遞給CUDA內核。如果你這樣做,這個問題有*無關*與atomicAdd – talonmies