DAY79:閱讀 Compute Capabilities

H. Compute Capabilities

The general specifications and features of a compute device depend on its compute capability (see Compute Capability).

Table 13 gives the features and technical specifications associated to each compute capability.

Floating-Point Standard reviews the compliance with the IEEE floating-point standard.

Sections Compute Capability 3.x, Compute Capability 5.x, Compute Capability 6.x, and Compute Capability 7.x give more details on the architecture of devices of compute capability 3.x, 5.x, 6.x, and 7.x respectively.

H.1. Features and Technical Specifications

.2. Floating-Point Standard

All compute devices follow the IEEE 754-2008 standard for binary floating-point arithmetic with the following deviations:

  • There is no dynamically configurable rounding mode; however, most of the operations support multiple IEEE rounding modes, exposed via device intrinsics;
  • There is no mechanism for detecting that a floating-point exception has occurred and all operations behave as if the IEEE-754 exceptions are always masked, and deliver the masked response as defined by IEEE-754 if there is an exceptional event; for the same reason, while SNaN encodings are supported, they are not signaling and are handled as quiet;
  • The result of a single-precision floating-point operation involving one or more input NaNs is the quiet NaN of bit pattern 0x7fffffff;
  • Double-precision floating-point absolute value and negation are not compliant with IEEE-754 with respect to NaNs; these are passed through unchanged;

Code must be compiled with -ftz=false, -prec-div=true, and -prec-sqrt=true to ensure IEEE compliance (this is the default setting; see the nvcc user manual for description of these compilation flags).

Regardless of the setting of the compiler flag -ftz,

  • Atomic single-precision floating-point adds on global memory always operate in flush-to-zero mode, i.e., behave equivalent to FADD.F32.FTZ.RN,
  • Atomic single-precision floating-point adds on shared memory always operate with denormal support, i.e., behave equivalent to FADD.F32.RN.

In accordance to the IEEE-754R standard, if one of the input parameters to fminf(), fmin(), fmaxf(), or fmax() is NaN, but not the other, the result is the non-NaN parameter.

The conversion of a floating-point value to an integer value in the case where the floating-point value falls outside the range of the integer format is left undefined by IEEE-754. For compute devices, the behavior is to clamp to the end of the supported range. This is unlike the x86 architecture behavior.

The behavior of integer division by zero and integer overflow is left undefined by IEEE-754. For compute devices, there is no mechanism for detecting that such integer operation exceptions have occurred. Integer division by zero yields an unspecified, machine-specific value.

http://developer.nvidia.com/content/precision-performance-floating-point-and-ieee-754-compliance-nvidia-gpus includes more information on the floating point accuracy and compliance of NVIDIA GPUs.

文備註/經驗分享:

本章表格主要說明了各種計算能力了下的卡的"特性"的異同。請注意該表格列出了目前所有支持的計算能力的卡的對比情況.而計算能力也往往是一般用戶口中的"代", 某代某代的卡如何如何。 它決定了用戶在編寫代碼的時候, 所能用到的特性; 有些特性是如此重要, 也往往決定了用戶購買的選擇.例如說, 用戶的代碼需要動態的細分處理, 需要使用動態並行(DP)的能力, 那麼根據此表格, 顯然就不能上3.0的一代Kepler.例如說, 前幾天我們論壇有個帖子, 有一個很奇特的需求, 要對一張圖片的所有像素的值進行求和. 我們當時在論壇提醒用戶, 需要注意整數類型的累加後的溢出情況(例如使用16-bit, 32-bit等等的整數類型), 則該用戶基於精度考慮, 可能會選擇使用浮點類型,特別的, 他可能會選擇double來進行簡單的原子累加(block內部進行無原子操作的規約累加, 然後就地在global memory可選的進行double累加原子操作, 規避二次kernel啓動), 則這個特性需要他至少購買計算能力6.0, 也就是Pascal這一代或者更高的卡,才能完成他的設計目標. 但是需要說明的是, 往往越新的一代卡, 折算到單位計算性能下的單價越貴.例如很多人現在已經拿到了2080(例如我們的七月, 括號裏的請刪除),它主打的是新的Tensor Core的特色(不用考慮RT Core, 用CUDA的人暫時用不到它), 而單精度的單位GFlops下的性能卻沒有顯著提升, 價格卻高了不少,則用戶實際上可以考慮購買上一代的1080之類的卡, 甚至同樣的預算能上1080Ti, 從而取得更好的性價比. 這樣根據實際項目對計算能力的主要特性的取捨不同, 用戶可以作出一定預算下的正確採購要求.

本表格需要特別注意的是兩個地方, 一個是半精度的支持, 一個是Tensor Core, 本章節的表格只作出了支持, 或者不支持的說明, 但實際上這兩點在支持的情況下, 外加計算能力5.3的特例(TX1)。 但這只是支持情況, 在支持的卡上, 至少保證了200%速率(相比該卡上的單精度速率)的半精度通用性能,但是在支持Tensor Core的卡上(主要是7.0和7.5, 後者也就目前我們說的圖靈, 包括你用的2080), 具有非常顯著的專用半精度性能, 也就是在矩陣乘法的情況下, 具有800%的半精度性能提升(同樣和該卡的單精度性能相比), 我們都知道, 特別的, 在深度學習的情況下, 主要就用兩個操作,一個是矩陣乘法, 一個是卷積, 而前者又可能佔用了大頭, 所以哪怕在通用的支持FP16半精度的情況下, 用戶也應該儘量考慮使用7.0+, 雖然本表格將5.3/6.x/7.x都簡單的劃成了支持半精度, 但用戶從實用的角度, 應當考慮購買新卡(或者新的嵌入式計算設備,例如還沒有出來的Xavier? 而不是5.X/6.X的TX1/TX2)。 類似的, 該表格還對7.X的Tensor Core支持統一劃成了支持, 但實際上這兩代的Tensor Core差別非常大,後一代的Tensor Core還支持INT8和INT4計算, 具有非常顯著的性能提升(例如INT8是1600%), 用戶在特定的需求的情況下, 例如密集的INT8計算, 應當只能考慮7.5的圖靈卡,(也包括一些挖礦用戶, 但好在現在挖礦不景氣, BTM之類的幣種正在被人忽視中, 否則Turing又會暴漲一段時間, 萬幸)。 此外, 考慮到現在的需要用的卡只有6.X+了, 該表格還沒有給出6.X+的主要特性: (1)支持深度學習指令(INT8), 至少具有400%的性能(例如__dp4a()函數, 手冊沒說), 該函數在Pascal(6.1)+上被支持, 而且比較通用(相比Tensor Core 2代的1600%極度專用化的INT8加速), 很多圖像處理的用戶應當考慮這點. (2)增強的Unified Memory, Pascal+的Unified Memory得到了極大增強, 但是這裏也只是簡單的和3.X/5.X等等一起, 簡單的標註了支持. 實際上Unified memory也可以劃成至少兩代, 3.X/5.X上的是初級的第一代, 6.X起具有非常顯著的特性提升. 這個等我們到了後面的Unified Memory再詳細說. 所以用戶對這個計算能力導致的特性異同的表格, 應當注意這種粗略的說法, 從而在選購和應用的時候作出更恰當的判斷.(實際上, 6.1的家用Pascal(不包含GP100), 這兩個特性是最主要的特性了. 去掉這兩個特性的Pascal等於只是Maxwell---但製程作出了優化而已(從28nm)) 第二個表格, 則說明了在CUDA使用的情況下, 一些硬件本身的限制情況.主要的大部分都是相同的(以前的計算能力還有複雜的啓動block形狀的限制不同, grid內部的blocks數量的限制不同, 這些現在如今都被取消了) 你可以看到, 標準的1024個線程的最大block大小, 最多(2^31 - 1)的X方向的Blocks數量,這些都減輕了用戶的記憶負擔, 和提高了程序的設計時候的思考量. 我說一下這個表格對普通的CUDA用戶所主要造成的影響: (1)Shared Memory / L1大小, 根據我們之前的章節, Shared Memory等於一種隨機訪問性能好(不同Banks的不同深度可以同時對用戶提供數據服務), 用戶可控的L1 Cache,而L1是全自動的. 所以不同的計算能力的情況下的不同的Shared Memory大小往往影響性能(一般情況下, 越大越好),但是這裏需要指出幾個例外,一個是計算能力3.7, 它具有超常的非常巨大的Shared Memory(112KB/SM), 而目前已知的3.7的卡只有K80,K80是NV對失敗的Kepler一代所作出的最後努力, 它將2個SM的資源累加到了一個SM上,所以你會看到在K80上具有驚人的Shared Memory大小.同理你會看到所有的寄存器大小都是256KB(也就是本表格的64K個),但只有K80是512KB的驚人大小, 這同樣是因爲它將2個SM的資源合成了1個SM. 所以說, 如果Kepler一代到現在還有價值的卡, 只有K80了. 然後同樣的你會看到7.X的Shared Memory似乎比較小.但是這裏需要指出的是, 7.X的SM裏面(Volta/Turing), SP數量只有減半的, 它們的大小實際上等同於乘以2,也就是相當於192KB和128KB的等價效果(而不是96KB和64KB), 這點需要特別注意. 類似的, 專業卡的6.0(GP100), 看上去Shared Memory還不如6.1的家用卡大,但實際上它的SM裏面的SP也是減半的, 同樣的SP規模折算下, 它具有雙倍的資源,實際上6.0和6.1對比, 等價於128KB vs 96KB, 而不是64KB vs 96KB. 這點用戶也需要知道. 此外, 部分嵌入式的設備, 具有較少的寄存器數量, (例如5.3和6.2的TX1/TX2,只有標準的每個block能用的寄存器數量的一半),這導致你至少需要在這些設備上, 每個SM能上2個block, 纔能有效的利用資源. 這點也需要注意一下. 注意最後該表格給出了一個最大512M條指令, 每個kernel的限制.這個實際上是很搞笑的, 哪怕在每條指令8B大小的情況下(例如6.X, 實際上稍微大一點), 512M條指令的Kernel, 編譯出來也有4GB大了,如果是7.X, 16B每條指令, 則有8GB那麼大, 我從來沒有見過如此巨大的kernel.但是考慮到總是有人喜歡問:"我的kernel能寫的多大" "我的kernel寫了這麼長沒事嗎"這樣的問題,該表格給出這種指標, 也很搞笑和無奈的.所以也挺好的. 此外, 關於本表格的能綁定的surface數量是16這個問題, 實際上是一個歷史問題, 具體可以參考我們之前章節的bindless, 無需綁定的那種surface, texture之類的, 後者沒有這種限制.也沒有每個綁定的紋理在啓動每個kernel所帶來的固定額外開銷.

關於第三部分, N卡所遵循的浮點標準(IEEE-754) 這裏主要說明了幾點: 沒有全局可以配置的動態的圓整(取整)模式,很多處理器上(例如X87?), 具有用戶可調的浮點取整模式, 但是N卡作爲GPU,沒有這種全局的模式, 而是每條指令都可以自行設定.回到具體的CUDA C用戶, 用戶可以注意到有些intrinsic functions具有_rz()之類的結尾, 就是起到這種作用的(歡迎參考我們之前的章節中說的4大圓整模式) 此外, 本章節說的NaN的問題, 部分處理器帶有多種NaN處理模式, 很多人以前在我們的羣裏, 三天兩頭的發, 我計算出錯了,出現了一些奇特的值(數值printf的時候帶有一些字母) 這裏需要注意Quiet NaN和Signaling NaN的區別, 後者還是NaN(異常值), 只是帶有額外的描述信息.(例如你0/0時候的結果,就屬於NaN) 本章節說明了, 如果單精度的運算過程中, 輸入運算數據有異常值NaN的, 結果都將只是Quiet NaN,具體的細節可以自行搜索一下.實際上wikipedia上有很詳細的描述, 如果我沒記錯的話. 然後還說了雙精度運算的時候, NaN數據會被Passthrough, 直接傳遞異常值的負載信息.這點也需要注意.但無論如何, 出現了NaN, 並導致NaN在程序的多次迭代計算中傳播開來,最後導致整體結果面目全非, 一般是用戶的鍋, 需要詳細檢查中間過程的結果數據, 和/或輸入值的數據, 做好它們的異常值處理.此外, 關於C++ Exception, 我們的GPU目前並不支持計算過程中的exception報告, 而是會產生Inf/Nan/0這種數據,這也是很正常的選擇, 因爲同時在GPU上執行的數據執行是海量的, 如果像常規的CPU那樣, 中途暫停一個或者多個kernel的計算, 報告CPU, 然後CPU單獨處理, 將會是災難性的, GPU啥都不用幹了.你會得到海量的併發異常的. 本段落還說了, 可以全局的用某些參數來控制精度信息(你可以選擇更高性能的, 但精度較低的; 和較慢的, 但精度較高的代碼生成,這點在之前說過, 請參考我們之前的相關章節. 注意該章節提到的SFU部分) 然後這裏強調的是, 原子操作有時具有較低的精度: 在global memory上的原子累加, 總是直接將denormals(或者叫subnormal number), 當成0來處理.而在Shared memory上的同樣的累加, 支持這種接近0的subnormal number, 並不將它們當成0來處理.(將很接近0的subnormal值當成0來處理會損失精度),

忘記了subnormal numbers是什麼了? 之前我們的章節提到過:當浮點數小到非常接近0的時候, 已經無法用原始的浮點格式(指數浮動)表示了, 此時爲了儘量保存有效數字, 將轉換成使用固定指數的定點數表示, 此時float之類的都將不再能保持23-bit這種有效數字位數, 但同時不將這些非常小的數值當成0處理, 而是儘量保存爲定點位數, 有一位算一位, 從而儘量能夠爲用戶保存精度。 當使用或者出現subnormal number的時候, 往往代表你需要轉換到下一級更高精度的數值方式了, 例如half可以考慮改用float, float可以考慮改用double 而double可以考慮改用float128(目前N卡並不能直接支持它), 但是可以用整數模擬,Turing的併發INT/FP整數單元, 可以在你同時使用常規FP單元硬件直接計算Float之類的同時,還能上INT單元模擬double和float128計算, 顯著提升性能, 並有效保護精度。 關於本段落裏面的FADD.F32.FTZ.RN和.RN,實際上是PTX的內容, 有興趣的用戶可以看一下PTX手冊(這本是CUDA C編程指南, PTX有非常詳細的, 類似本書的另外一本)

有不明白的地方,請在本文後留言

或者在我們的技術論壇bbs.gpuworld.cn上發帖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章