CUDA程式性能分析-矩陣乘法
前言
矩陣乘法非常适合在GPU上并行運作,但是使用GPU并行後能獲得多大的性能提升?本文将通過一些實驗分析CUDA程式的性能。
測試環境
本文使用Dell XPS 8700作為測試機,相關配置如下:
. | |
---|---|
型号 | Dell XPS 8700 |
CPU | Intel Core i7-4970 3.6GHz |
主存 | 16GB |
GPU | GeForce GTX 750Ti |
OS | Windows 10 64bit |
CUDA | CUDA 8.0 |
帶寬測試
使用CUDA Toolkit提供的示例程式bandwidthTest測試可分頁記憶體(Pageable)和鎖頁記憶體(Page-lock or Pinned)的帶寬,測試結果如下:
從上圖可以看出,鎖頁記憶體對帶寬的提升是非常大的,是以當一個程式的性能瓶頸是資料傳輸時,就應該考慮是否應該使用鎖頁記憶體。當然,使用鎖頁記憶體是有代價的——該記憶體空間不能換頁,當大量使用時會導緻記憶體耗盡而是程式崩潰。
矩陣乘法性能對比
測試了5個不同版本的矩陣乘法的性能:numpy、C++、CUDA無優化(CUDA1)、CUDA使用共享記憶體優化(CUDA2)、cuBLAS,由于原生Python版本的程式實在太慢了,故放棄之。CUDA和cuBLAS版本的矩陣乘法可以從CUDA Toolkit提供的示例程式matrixMul、matrixMulCUBLAS找到,當然需要做一些修改。5個版本的測試結果如下:
從上圖可以看到,3個GPU版本的性能都比CPU(C++)版本高,尤其是在資料量變大的時候,如當資料量大于1024*1024時,C++版本的運作時間急劇上升。對比不使用共享記憶體和使用共享記憶體優化的版本可以看到,在資料量小的時候兩個版本看不出差異,而當資料量越來越大的時,性能差異就很明顯。使用共享記憶體優化的版本明顯優于不優化的版本,這是因為從全局記憶體通路資料是非常慢的,而共享記憶體就相對快多了,當所有的線程都重複從全局記憶體讀取資料勢必導緻全局記憶體總線擁堵,而且記憶體通路也不能合并,導緻大量線程被挂起,進而降低性能。共享記憶體是程式員可以控制的高速緩存,應該可能地應用它以優化程式的性能。另外,使用cuBLAS似乎比自己實作一個算法的性能更高,這是因為這些庫都是擁有豐富程式設計和優化經驗的進階程式員編寫的,是以當考慮自己實作一個算法的時候先看看是否有現成的庫可以使用,有時候費力并不一定讨好 :D。
比較戲劇性的是Numpy,它的表現完全出乎我的意料,居然戲劇性地接近了比GPU版本的性能,關于原因還有待研究。這也告訴我們,使用Python時遇到數學計算還是盡量使用Numpy而不是python的math。當然如果你的計算機配備GPU或多核CPU(貌似現代GPU都是多核的)也可以考慮Numba加速Python程式,參考使用Python寫CUDA程式。
結語
本文主要記錄了本人測試CUDA程式性能的結果,并對結果進行了分析,從測試結果和分析可以為并行程式和優化性能帶來一些啟示。
本文完整代碼可在Github上下載下傳。