cuda第一次计算耗时_CUDA优化的冷知识10 | GPU卡和Jetson上显存优化的特色
這一系列文章面向CUDA開發者來解讀《CUDA C?
Best Practices Guide》 (CUDA C最佳實踐指南)
大家可以訪問:
這是一本很經典的手冊。
CUDA優化的冷知識|什么是APOD開發模型?
CUDA優化的冷知識2| 老板對不起
CUDA優化的冷知識 3 |男人跟女人的區別
CUDA優化的冷知識 4 | 打工人的時間是如何計算的
CUDA優化的冷知識 5 | 似是而非的計時方法
CUDA優化的冷知識 6 |GPU端的CUDA Event計時
CUDA優化的冷知識 7 |GPU端Event計時的重要特色
CUDA優化的冷知識 8 |GPU顯存的特色
CUDA優化的冷知識9 |GPU顯存的粒度
我們下面就繼續進一步的, 說說Global Memory的相關優化.
要說對它的優化, 我們得先知道Global Memory是什么, 和很多人的印象里的不同, 它不一定是顯存. 還可能是映射的內存. (例如zero-copy時候的手工分配的, 和退化的Unified Memory的情況). 我們主要說一下當Global Memory是顯存, 和是zero-copy的情況, 而暫時忽略是退化的Unified Memory的情況。
說一下這兩者時候的注意事項和優化.
首先本實踐手冊這里, 提到了zero-copy內存, 這種是鎖定在物理頁面中, 而不能被交換到磁盤上, 同時又能被GPU設備, 直接訪問到的內存(映射成了global memory)。
這種內存, 具有多個特點.
先說一下實體顯卡上的, 再說一下我們的Jetson上的。
在實體顯卡上, 因為卡是通過PCI-E連接到CPU的, 此時的一切傳輸(從內存到顯存), 均需要通過PCI-E進行. 而PCI-E的帶寬非常有限. 通常只有16GB/s的理論帶寬. 注意手冊這里第一次給出了實際能達到的, 在PCI-E 3.0 x16下的傳輸帶寬, 往往是只有12GB/s左右, 這個結果是和實際日常使用中的情況是一樣的. 手冊這里給出的的確是比較準確的數字. 而這個帶寬, 很多時候, 只有通過鎖定在頁面中的緩沖區傳輸, 才能達到的, 為何? 主要是這個涉及了CUDA C編程指南中, 和CUDA Runtime API手冊中的最前面說的一些情況. 我簡單這里重復一下吧.
一個是作為PCI-E上的GPU設備, 他用自帶的DMA引擎, 進行BUS Mastering的時候, 本身就只能訪問物理頁面(或者說, 物理頁面范圍). 而不能支持CPU端的虛擬內存. (否則它將需要理解CPU端的頁表結構等一系列問題, 才能自動轉換)。我們知道當年的某藍色巨人的XGA顯卡, 作為它的8514顯卡的繼承人, 具有CPU端的虛擬內存支持, 并重新實現了兼容于x86 CPU的頁表和相應的CR寄存器,作為當年的該機型的用戶, 超越了20年的感動依然在心中。然而其他所有后來的顯卡都沒有這個特點, 因此他們就只能用自己的DMA Engines訪問物理內存(好吧, 某些DGX例外). 因此, 當用戶要求傳輸一段普通的可換頁內存的時候, 要么顯卡驅動內部, 先將該段內存緩沖區的內容, 復制到自己內部的一個小的鎖定的物理頁面范圍上去, 然后再從這里安全的傳輸; 要么就是就地嘗試鎖定, 然后傳輸. 但前者多了一次內存內存的傳輸, 后者則有鎖定和解鎖開銷(這里面的細節可以看CUDA Runtime API手冊的前面, 歷年GTC也有過詳細描述) 。
前者幾乎將內存的有效帶寬降低了一半,例如我們上次距離的那個68GB/s峰值的內存的機器(4通道DDR4-2133), 這樣一倒騰, 內存帶寬就實際上只有34GB/s了. 哪怕你不考慮在CPU上運行的應用程序的需要, 光這點帶寬, 傳輸兩三張卡就撐不住了,而使用這種鎖定了頁面的內存, 則可以就地開始傳輸, 節省了一半的內存的帶寬, 因為過程從內存->內存->顯存, 變成了內存->顯存了. 還是很容易喂飽你的卡們的. 這個是很適合在實體GPU上傳輸的特性。
這是對于實體卡說的,對于我們的Jetson產品, 實際上是并沒有獨立的顯存和內存的, 也不是通過PCI-E總線傳輸的, CPU和GPU都在SoC的內部, 共享SoC提供的內存(顯存)控制器. 此時如果你照搬之前的經驗, 直接來一個cudaMemcpy*()系列函數. 則實際上你無辜的在該內存(顯存)內部, 倒騰了一次. 無任何意義. 當時他們提出, 一定要利用頁面鎖定內存, 能無傳輸的就地訪問的特性(俗稱zero-copy, 可以看成是最最簡化版的Unified Memory). 取消掉這個在Jetson上的無辜傳輸. 然后讓GPU就地訪問CPU的工作數據. 這點還是非常重要的。
不過在Jetson系列產品上, 直接使用zero-copy的方式會禁用GPU的緩存(L2)的, 不如后來的更好用一點(但限制更大)的Jetson上的Unified Memory方式好(也是直接共享, 但啟用L2, 但會禁用CPU-GPU同時訪問). 這點等我們到了Unified Memory的時候再說。
好了.回到本章節前面的頁面鎖定內存的傳輸和作為zero-copy上的特性內容。
注意本章節這里提到了, 要在CUDA 2.2+, 無顯存的那種集成顯卡上, 使用zero-copy, 云云的. 而沒有提到Jetson. 這是因為手冊10年來沒改的緣故了.
我們現在已經將近10年買不到這種無顯存的卡了(以前一些筆記本上有),而Jetson產品也已經普及。
所以我們這里做了調整, 取消了手冊上說的過時的不存在的內容, 而增加了Jetson上應當考慮zero-copy就地使用的做法.
此外, 手冊上介紹了如何能利用頁面鎖定的內存, 有效的進行計算和傳輸重疊的特性. 手冊這里給出了一個很好用的東西:
就是當我們只有1個kernel要啟動, 和1份緩沖區要使用的時候, 如果能讓這個進行多次傳輸和計算的重疊. 本實踐手冊這里給出了如下建議: 即將你的kernel修改里面的線程或者block的坐標/下標映射, 將原本一次啟動的kernel, 工作于一個大緩沖區上, 改成N次啟動(注意每次里面的坐標的變化), 并每次傳輸1/N內容的緩沖區, 這樣可以盡量達到傳輸和計算的重疊. 這個是一個很好的實踐方式. 因為很多時候, 你想利用傳輸和計算重疊這個優化, 但是你找不到多余的kernel計算任務, 和多余的傳輸任務來重疊,此時, 你應當考慮本手冊中的, 拆分計算規模, 和拆分成1/N每次傳輸的建議. 這種建議還是很好的. 當然這樣做, 你需要注意坐標的偏移和變化. 不要計算錯了.
實際上, 在某OpenCL對等的規范中, 在友商家的卡上, 我們可以直接在啟動kernel的時候, 提供這個坐標偏移量. 從而完成類似的操作, 而不需怎么改動代碼. 所以你看, 這是一個相當實用的東西, 實用到友商家已經提供了API以方便你這樣做了.
此外, 手冊還提供了另外一個建議, 就是直接不要傳輸了, 直接就地使用. 因為zero-copy可以以一定的粒度, 直接從內存跨越PCI-E到L2(然后進一步到SM中). 這樣根據手冊這里的說法, 能在kernel的指令級別, 實現計算和傳輸的重疊. 但是根據我們的實踐, 大部分的使用效果實際上并不好. 我們懷疑是可能是跨越PCI-E帶來了更大更難掩蓋的延遲或者其他因素, 這些需要等待確定. 但是手冊中不強調的另外一個用法, 實際上效果非常好. 即將zero-copy作為容納結果數據的, 寫入的緩沖區. 這種可以將結果的回傳, 和kernel的計算, 也在kernel的指令級別, 進行重疊. 而無需你事后開一個異步傳輸在某流中. 在我們的日常實踐中, 這種具有非常好的使用效果. 好到了很多人都發現了這點. 并且在arvix上發文, 用FPGA攔截了zero-copy作為寫入結果的緩沖區的時候, kernel的寫入, 在指令級別的重疊, 通過L2, 跨越PCI-E回傳的時候的情況, 并做了分析. 我們現在大致知道, 根據此文(我不記得番號了, 但是容易找到. 用FPGA + Zero-Copy的字樣, 近期文章),
手冊中的這種作為直接回寫操作的做法, L2會產生跨越PCI-E的32B, 64B, 128B大小的傳輸的.
然后本文章還分析了, 為何只能達到約12GB/s, out of 16GB/s的原因(因為PCI-E的包大小的問題的浪費, 而不是編碼問題). (注意這是說的PCI-E 3.0, 而不是4.0, 后者可能大約達到25GB/s, 這是根據我們客戶的反饋, 而不是實際我們的測試).
大致是分析完了顯存的特性、一個令人意外的(非常分散的不合并讀寫的優勢)、 兩種global memory中的前一種, 以及它的傳輸上的好用的地方, 和在Jetson上的應用。
總結
以上是生活随笔為你收集整理的cuda第一次计算耗时_CUDA优化的冷知识10 | GPU卡和Jetson上显存优化的特色的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 获取族_批量添加族参数(上)
- 下一篇: 冻结拆分_冻结首行与尾行?还有能这种操作