程序猿玩家細說GTX 680輕取百萬線程代碼
說起通用計算、并行計算、加速計算,NVIDIA CUDA 無疑是很多開發人員的首選。雖然還有開放的 OpenCL,但在開發環境方面還不夠,CUDA 則在經過大力推廣后擁有了不錯的群眾基礎。GeForce GTX 600 時代雖然這方面的宣傳似乎少了很多,開普勒架構的浮點性能看起來也不強,但其實在并行計算方面仍然有很多進步的,其中蘊藏著不少能量,比如費米架構首創性 地加入了和處理器一樣的統一讀寫二級緩存,GK104核心更把底層的 SMX 進行了變革。
今天就有一位技術宅程序猿同學,利用一塊 GeForce GTX 680 4GB,展示了如何在開普勒上取得百萬級別的線程代碼。看不懂不要緊,內行看門道,外行看熱鬧。
據說,技術宅的廁紙用完了之后就會用書本。
技術宅受到刺激后,迷上了超大規模程序設計,那個叫什么 CUDA 神秘兮兮的東西。
平臺艷照。
CUDA 的環境配置:首先安裝 CUDA 工具箱,然后安裝顯卡驅動,最后安裝 CUDA SDK。前兩步必不可少,第三步可以省略。
G80、GT200的 SM 架構差異,導致了 CUDA 程序上的不同優化。
老架構就不花時間去討論了,直奔在通用計算大放異彩的費米架構,革命性的統一讀寫一級、二級緩存有些模仿 CPU 設計的味道。下面結合硬件來說說 CUDA 如何根據它來優化。
費米的 SM 擁有 3 萬個高速寄存器,保證了線程的快速切換,要知道八核心 CPU 也不過幾百個而已。16路高速存儲通道來并行操作 64KB 的片上高速緩存,速度可達到 1TB/s級別。
開普勒再度加強,在晶體管數量控制在 35.4 億個的情況下竟然塞進了比費米多一倍的 CUDA 核心,寄存器也翻番達到6.5萬個,存儲通道也多了一倍。
要讓 CUDA 程序為開普勒架構優化,首要任務是讓 Block 里面的線程盡量的多。GT200 SM 允許的活動線程是 1024 個,費米優化的代碼可以增加到 1536 個,開普勒則進一步提高到 2048 個(注:GK110核心也會如此)。
這個是軟件層次對應的硬件層次。Block 編程上的線程塊在 SM 里分時運行,一個 CUDA 程序會有多個 blcok 并行運行,而每個 block 線程塊又包含了數十到上百的線程,也就構成了 CUDA。
不同架構對應不同的計算規格,代碼優化也要針對性地進行,比如開普勒可以支持更大的 block 內部線程,可以讓更多線程進行片上同步工作,另外費米和開普勒有 DRAM 緩存,所以對 DRAM 優化的力度沒有 G80 那么吃力。
開普勒在 CUDA 上加入了更大的革新,特別是支持多內核函數的并行執行。注意,一個 CUDA 內核就是一個可具備百萬線程的并行程序,而這些內核函數更可以并行執行。
開普勒在內核函數執行引擎上比費米有了大幅度的加強。
從 CUDA 的發展角度看,NVIDIA 一共經歷了四代架構更新,而唯一不變的是 warp 硬件指令的寬度。(這里和 AMD 的稍微不同,后者硬件指令寬度是 64)。
想要 CUDA 編程的童鞋可以開始了。安裝好驅動、工具箱后,就可以安裝C/C++編輯器了。用微軟的 Visual Studio 比較方便,只是它本身不支持 CUDA 語法,需要在工具箱里面找到語法配置文件,配置一下就可以了。
其實,CUDA 代碼也不神秘,就是C和一些C的擴展而已,懂C的朋友很容易就明白了,不過 CUDA 代碼編譯的系統執行文件有點小小麻煩,因為需要調用 2 個編譯器,一個是C/C++,另外一個是 GPU 編譯器。還好NVDIA 提供了比較方面的 NVCC 工具,這是一個半編譯和連接工具,主要用語分離 CPU 和 GPU 代碼,然后把 CPU 代碼給 VS 編譯,然后自己編譯 GPU 代碼。編譯后連接好就可以編程執行代文件了。
這是 NVIDIA 的性能調試工具,非常不錯,能夠可視化分析硬件的使用率。
程序的產生都可以清楚分析,這是一個 CUDA 二維傅立葉變換的例子。不過計算單元的使用率不高,雖然很密集地運行 kernel,但是每個 kernel 的執行時間不長,不到 30 微秒。
用性能工具來測試 CUDA 體渲染程序。
開普勒有多 kernel 并行運行的優勢。
黃色感嘆號表明程序可能有能夠加強性能的改進之處。
載入粒子模擬仿真。
程序性能分析。
這一段小代碼讓 GPU 所有的 CUDA 核心都運行一個內循環加法。當然,真正的并行程序并沒有那么簡單。這里是主要是用性能工具來分析 GPU ALU 的使用率。
代碼主要一一對應地生成 1536 個線程,每個線程做一個內循環,模擬 GPU 真實的負載工作。另外如果需要,可以調整 Grid 網格的規格增加線程,要生成一個百萬線程,只需要在內核函數輸入 1000000/192=540個 block 線程塊就可以了。GPU 的最大優勢是可以實現線程的高速切換,速度是 CPU 的上千到幾千倍。
最后,技術宅跟我們分享了 CUDA 的一些感覺。CUDA 是一個異構的執行體系,就是說 CUDA 里面你既要寫 CPU 代碼,也要內嵌 GPU 內核代碼。它是用來發揮 CPU、GPU 兩種架構的長處的。你 認為 CPU 執行更好的部分,可以在函數用 CPU 代碼實現;你認為某部分交給 GPU 執行跟好,就可以寫成 GPU 代碼。打個比方,某個負責引用需要一個并行度極高的運算和一個串行讀很高的復雜運算構成,那就可以先通過 PCI-E傳輸數據給 GPU 并行執行,然后返回給 CPU 做執行,最終輸出結果。CUDA 的另外一個用法是 CUDA 圖形相互操作,比如支持 PhysX 物理加速的游戲就是,在圖形渲染哪里和 CUDA 物理加速相互操作。
看到這里,是不是發現自己對 CUDA 有了更加深刻的認識?其實它也不是多么神秘的,就是個開發環境而已。