GPU CUDA之——深入理解threadIdx


http://blog.csdn.net/canhui_wang/article/details/51730264

摘要

本文主要講述CUDA的threadIdx。

 

1. Grid,Block和Thread三者的關系

其中,一個grid包含多個blocks,這些blocks的組織方式可以是一維,二維或者三維。任何一個block包含有多個Threads,這些Threads的組織方式也可以是一維,二維或者三維。舉例來講:比如上圖中,任何一個block中有10個Thread,那么,Block(0,0)的第一個Thread的ThreadIdx是0,Block(1,0)的第一個Thread的ThreadIdx是11;Block(2,0)的第一個Thread的ThreadIdx是21,......,依此類推,不難整理出其中的映射公式(表達式已在代碼中給出)。

 

2. GridID,BlockID,ThreadID三者的關系

ThreadID是線性增長的,其目的是用於在硬件和軟件上唯一標識每一個線程。CUDA程序中任何一個時刻,每一個線程的ThreadIdx都是特定唯一標識的!grid,block的划分方式不同,比如一維划分,二維划分,或者三維划分。顯然,Threads的唯一標識ThreadIdx的表達方式隨着grid,block的划分方式(或者說是維度)而不同。下面通過程序給出ThreadIdx的完整的表達式。其中,由於使用的時候會考慮到GPU內存優化等原因,代碼可能也會有所不同,但是threadId的計算的表達式是相對固定的。

 

[cpp]  view plain  copy
  1. /**************************************************************/  
  2. // !!!!!!!!!!!!!!注意!!!!!!!!!!!!!!!!  
  3. /**************************************************************/  
  4. // grid划分成a維,block划分成b維,  
  5. // 等價於  
  6. // blocks是a維的,Threads是b維的。  
  7. // 這里,本人用的是第一中說法。  
  8. /**************************************************************/  
  9.   
  10.   
  11. // 情況1:grid划分成1維,block划分為1維。  
  12. __device__ int getGlobalIdx_1D_1D() {  
  13.     int threadId = blockIdx.x *blockDim.x + threadIdx.x;  
  14.     return threadId;  
  15. }  
  16.   
  17. // 情況2:grid划分成1維,block划分為2維。  
  18. __device__ int getGlobalIdx_1D_2D() {  
  19.     int threadId = blockIdx.x * blockDim.x * blockDim.y  
  20.         + threadIdx.y * blockDim.x + threadIdx.x;  
  21.     return threadId;   
  22. }  
  23.   
  24. // 情況3:grid划分成1維,block划分為3維。  
  25. __device__ int getGlobalIdx_1D_3D() {  
  26.     int threadId = blockIdx.x * blockDim.x * blockDim.y * blockDim.z  
  27.         + threadIdx.z * blockDim.y * blockDim.x  
  28.         + threadIdx.y * blockDim.x + threadIdx.x;  
  29.     return threadId;  
  30. }  
  31.   
  32. // 情況4:grid划分成2維,block划分為1維。  
  33. __device__ int getGlobalIdx_2D_1D() {  
  34.     int blockId = blockIdx.y * gridDim.x + blockIdx.x;  
  35.     int threadId = blockId * blockDim.x + threadIdx.x;  
  36.     return threadId;  
  37. }  
  38.   
  39. // 情況5:grid划分成2維,block划分為2維。  
  40. __device__ int getGlobalIdx_2D_2D() {  
  41.     int blockId = blockIdx.x + blockIdx.y * gridDim.x;  
  42.     int threadId = blockId * (blockDim.x * blockDim.y)  
  43.         + (threadIdx.y * blockDim.x) + threadIdx.x;  
  44.     return threadId;  
  45. }  
  46.   
  47. // 情況6:grid划分成2維,block划分為3維。  
  48. __device__ int getGlobalIdx_2D_3D() {  
  49.     int blockId = blockIdx.x + blockIdx.y * gridDim.x;  
  50.     int threadId = blockId * (blockDim.x * blockDim.y * blockDim.z)  
  51.         + (threadIdx.z * (blockDim.x * blockDim.y))  
  52.         + (threadIdx.y * blockDim.x) + threadIdx.x;  
  53.     return threadId;  
  54. }  
  55.   
  56. // 情況7:grid划分成3維,block划分為1維。  
  57. __device__ int getGlobalIdx_3D_1D() {  
  58.     int blockId = blockIdx.x + blockIdx.y * gridDim.x  
  59.         + gridDim.x * gridDim.y * blockIdx.z;  
  60.     int threadId = blockId * blockDim.x + threadIdx.x;  
  61.     return threadId;  
  62. }  
  63.   
  64. // 情況8:grid划分成3維,block划分為2維。  
  65. __device__ int getGlobalIdx_3D_2D() {  
  66.     int blockId = blockIdx.x + blockIdx.y * gridDim.x  
  67.         + gridDim.x * gridDim.y * blockIdx.z;  
  68.     int threadId = blockId * (blockDim.x * blockDim.y)  
  69.         + (threadIdx.y * blockDim.x) + threadIdx.x;  
  70.     return threadId;  
  71. }  
  72.   
  73. // 情況9:grid划分成3維,block划分為3維。  
  74. __device__ int getGlobalIdx_3D_3D() {  
  75.     int blockId = blockIdx.x + blockIdx.y * gridDim.x  
  76.         + gridDim.x * gridDim.y * blockIdx.z;  
  77.     int threadId = blockId * (blockDim.x * blockDim.y * blockDim.z)  
  78.         + (threadIdx.z * (blockDim.x * blockDim.y))  
  79.         + (threadIdx.y * blockDim.x) + threadIdx.x;  
  80.     return threadId;  
  81. }  

 

 

3. GPU Threads與CPU Threads的比較

GPU Threads的生成代價小,是輕量級的線程;CPU Threads的生成代價大,是重量級的線程。CPU Threads雖然生成的代價高於GPU Threads,但其執行效率高於GPU Threads,所以GPU Threads無法在個體的比較上取勝,只有在數量上取勝。在這個意義上來講,CPU Threads好比是一頭強壯的公牛在耕地,GPU Threads好比是1000頭弱小的小牛在耕地。因此,為了保證體現GPU並行計算的優點,線程的數目必須足夠多,通常至少得用上1000個GPU線程或者更多才夠本,才能很好地體現GPU並行計算的優點!

 

4. GPU Threads的線程同步

線程同步是針對同一個block中的所有線程而言的,因為只有同一個block中的線程才能在有效的機制中共同訪問shared memory。要知道,由於每一個Thread的生命周期長度是不相同的,Thread對Shared Memory的操作可能會導致讀寫的不一致,因此需要線程的同步,從而保證該block中所有線程同時結束。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM