CUDA 學習(六)、線程網格

一、概述

       一個線程網格是由若干線程塊組成的,每個線程塊是二維、三維的,擁有X軸、Y軸、Z軸。此時,每次最多能開啓Y*X*Z*T 個線程。

       通常線程塊中線程數量最好是一個線程束大小的整數倍,即32 的整數倍。由於設備是整個線程束爲單位進行調度,如果我們不把線程塊上的線程數目設成32的整數倍,則最後一個線程束中有一部分線程是沒有用的,因此我們必須設置一個限制條件進行限制,防止處理的元素超出X軸方向上所規定的範圍。

        在程序中,要儘量避免使用小的線程塊,因爲這樣做無法充分利用硬件。比如,一張圖片分辨率爲1920*1080,我們可以分配 dim3 block_num(1080, 10) ;   dim3  thread_num(192, 1);

      

在當前費米架構的硬件上,一個SM可以處理8個線程塊,所以上述程序從應用層的角度來說一共需要1350個(總共10800個線程塊 / 每個SM 能調度的8個線程塊)SM來完成實現並行。


二、線程與線程塊

       CUDA 中線程與線程塊到底有什麼聯繫?CUDA 的設計是用來將數據分解到並行的線程與線程塊中。它允許我們定義一維、二維、三維的索引(Y*X*T)來方便我們在程序中引用一些並行結構。這樣就使得我們程序的結構和內存數據的分佈建立一一映射,處理的數據能被分配到到單獨的SM 中。不論是在GPU上還是在CPU上,讓數據與處理器保存緊密聯繫能使性能得到很大的提升。

       不過,在對數組進行佈局的時候,有一點需要我們特別注意,那就是數組的寬度值最好是線程束大小的整數倍。如果不是,填補數組,使它能充滿最後一個線程束。但是這樣做會增加數據集的大小。此外,我們還需要注意對填充單元處理,它和數組中其他單元的處理不同的。


三、X 與Y 方向的線程索引

       在一個線程塊上分佈一個二維數組也意味着需要兩個線程索引,這樣我們纔可以用到二維的方式訪問數組:

   

      注意blockDim.x 與 blockDim.y 的使用,這個結構體是由CUDA 運行時庫提供的,分佈表示X軸和Y軸這兩個維度上線程塊的數目。

      例如,計算一個32*16 維的數組,假設調度四個線程塊,我們可以有下面的分佈方式:

    

       在實際中長方形的佈局比正方向的佈局優越,這是爲什麼呢?主要有兩個原因:第一,同一個線程塊中的線程可以通過共享內存進行通信,這是線程協作中一種比較快的方式。第二,在同一個線程束的線程存儲訪問合併在一起了,而在當前費米架構的設備中,高速緩存存儲器的大小是128個字節,一次直接訪問連續的128個字節比兩個分佈訪問64個字節要高效得多。在正方形的佈局中,0-15號線程映射在一個線程塊中,它們訪問一塊內存數據,但與這塊內存相連的數據區則是由另一個線程塊訪問的,因此,這兩塊連續的內存數據通過兩次存儲訪問才獲得,而在長方形的佈局中,這只需要一次存儲訪問的操作。

      這兩種佈局方式,線程塊和網格配置如下:

       

       線程網格、線程塊及線程的維度如下:

        

     其中:

    gridDim.X ----線程網格X維度上線程塊的數量

    gridDim.Y ----線程網格Y維度上線程塊的數量


    blockDim.x ---一個線程塊X維度上的線程數量

    blockDim.y ---一個線程塊Y維度上的線程數量


    threadIdx.x ---一個線程塊X維度上線程索引

    threadIdx.x ---一個線程塊Y維度上線程索引


通過找出當前的行索引,然後乘以每一行的線程總數,最後加上在X軸方向上的偏移,我們便可以計算出相對於整個線程網格的絕對線程索引。具體點如下:

   thread_idx = ((gridDim.x * blockDim.x) * idy) + idx;

  其中:

         idx = (blockIdx.x * blockDim.x) + threadIdx.x;

         idy = (blockIdx.y * blockDim.y) + threadIdx.y;



  



發佈了119 篇原創文章 · 獲贊 55 · 訪問量 43萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章