技术开发 频道

GPU 的硬體架構

  Texture

  CUDA 支援 texture。在 CUDA 的 kernel 程式中,可以利用顯示晶片的 texture 單元,讀取 texture 的資料。使用 texture 和 global memory 最大的差別在於 texture 只能讀取,不能寫入,而且顯示晶片上有一定大小的 texture cache。因此,讀取 texture 的時候,不需要符合 coalesced 的規則,也可以達到不錯的效率。此外,讀取 texture 時,也可以利用顯示晶片中的 texture filtering 功能(例如 bilinear filtering),也可以快速轉換資料型態,例如可以直接將 32 bits RGBA 的資料轉換成四個 32 bits 浮點數。

  顯示晶片上的 texture cache 是針對一般繪圖應用所設計,因此它仍最適合有區塊性質的存取動作,而非隨機的存取。因此,同一個 warp 中的各個 thread 最好是讀取位址相近的資料,才能達到最高的效率。

  對於已經能符合 coalesced 規則的資料,使用 global memory 通常會比使用 texture 要來得快。

  運算單元

  Stream processor 裡的運算單元,基本上是一個浮點數的 fused multiply-add 單元,也就是說它可以進行一次乘法和一次加法,如下所示:

  a = b * c + d;

  compiler 會自動把適當的加法和乘法運算,結合成一個 fmad 指令。

  除了浮點數的加法及乘法之外,整數的加法、位元運算、比較、取最小值、取最大值、及以型態的轉換(浮點數轉整數或整數轉浮點數)都是可以全速進行的。整數的乘法則無法全速進行,但 24 bits 的乘法則可以。在 CUDA 中可以利用內建的 __mul24 和 __umul24 函式來進行 24 bits 的整數乘法。

  浮點數的除法是利用先取倒數,再相乘的方式計算,因此精確度並不能達到 IEEE 754 的規範(最大誤差為 2 ulp)。內建的 __fdividef(x,y) 提供更快速的除法,和一般的除法有相同的精確度,但是在 2216 < y < 2218 時會得到錯誤的結果。

  此外 CUDA 還提供了一些精確度較低的內建函式,包括 __expf、__logf、__sinf、__cosf、__powf 等等。這些函式的速度較快,但精確度不如標準的函式。詳細的資料可以參考 CUDA Programming Guide 1.1 的 Appendix B。

  和主記憶體間的資料傳輸

  在 CUDA 中,GPU 不能直接存取主記憶體,只能存取顯示卡上的顯示記憶體。因此,會需要將資料從主記憶體先複製到顯示記憶體中,進行運算後,再將結果從顯示記憶體中複製到主記憶體中。這些複製的動作會限於 PCI Express 的速度。使用 PCI Express x16 時,PCI Express 1.0 可以提供雙向各 4GB/s 的頻寬,而 PCI Express 2.0 則可提供 8GB/s 的頻寬。當然這都是理論值。

  從一般的記憶體複製資料到顯示記憶體的時候,由於一般的記憶體可能隨時會被作業系統搬動,因此 CUDA 會先將資料複製到一塊內部的記憶體中,才能利用 DMA 將資料複製到顯示記憶體中。如果想要避免這個重複的複製動作,可以使用 cudaMallocHost 函式,在主記憶體中取得一塊 page locked 的記憶體。不過,如果要求太大量的 page locked 的記憶體,將會影響到作業系統對記憶體的管理,可能會減低系統的效率。

0
相关文章