| 
#include "cuda_runtime.h" 
#include "device_launch_parameters.h" 
#include <stdio.h> 
#define ThreadSize 1000 
#define BlockSize  10000 
#define ArraySize 10 
__global__ void incKernel(int *a) 
{ 
     int i =
  (blockIdx.x*blockDim.x + threadIdx.x) % ArraySize; 
     a[i] = a[i] + 1; 
} 
int main() 
{ 
     int host_a[ArraySize]; 
     int *dev_a = 0; 
     float elapsedTime; 
     // setup performance meter from CUDA ---------- 
     cudaEvent_t
  start, stop; 
     cudaEventCreate(&start); 
     cudaEventCreate(&stop); 
     cudaSetDevice(0); 
     cudaMalloc((void**)&dev_a, ArraySize * sizeof(int)); 
     for (int run = 0; run <
  10; run++) { 
         cudaMemset(dev_a,
  0, ArraySize * sizeof(int));         //clear  
         cudaEventRecord(start,
  0); //keep start time 
         incKernel
  << <BlockSize, ThreadSize >> > (dev_a); //calculate 
         cudaEventRecord(stop,
  0); //keep stop time 
         cudaEventSynchronize(stop);
  //wait stop event      
         cudaEventElapsedTime(&elapsedTime,
  start, stop);   
         cudaMemcpy(host_a,
  dev_a, ArraySize * sizeof(int), cudaMemcpyDeviceToHost); 
         //Print result 
         printf("run {%d}: ",run); 
         for (int i = 0; i < ArraySize; i++) { 
              printf("%d ", host_a[i]); 
         } 
         printf(" t=%f\n",elapsedTime); 
     } 
     //cudaDeviceSynchronize(); 
     getchar(); 
     cudaFree(dev_a); 
     return 0; 
} | 
執行結果如下:
這裡可以發現, 雖然每個陣列元速執行的程式碼都一樣, 結果卻不相同. 如果要得到正確答案, 需要用到互斥機制, 在以 CPU 計算環境中, 多由作業系統負責管理, 而在 CUDA 中, 用硬體用 atomic 運算來解決這個問題, 程式修改如下:
| 
int atomicAdd(int* address, int val); 
__global__ void incKernel(int *a) 
{ 
     int i =
  (blockIdx.x*blockDim.x + threadIdx.x) % ArraySize; 
     //a[i] = a[i] + 1; 
     atomicAdd(&a[i], 1); 
} | 
因為 atomic 運算屬於 architecture 指令, 如果不自行宣告 header 亦可, compiler 會自動處理, 只是編輯時會看到 Visual Studio 的警告訊息. 修改後的執行結果如下:
結果就正確了, 速度快慢則不一定, 在這個例子中是變快了
 
沒有留言:
張貼留言