我有一個應用程序,可以在用戶系統中的GPU之間分配處理負載。基本上,每個GPU有一個CPU線程,當由主應用程序線程週期性地觸發時,它啓動一個GPU處理間隔。使用2個GPU同時調用cudaMalloc時的性能不佳
考慮以下圖像(使用NVIDIA的CUDA分析器工具生成),以GPU處理間隔爲例 - 此處應用程序使用單個GPU。
正如你所看到的GPU處理時間的很大一部分是由兩個分揀作業消耗,我使用這個(推力:: sort_by_key)的推力庫。另外,在啓動實際排序之前,它看起來像thrust :: sort_by_key在引擎蓋下調用一些cudaMallocs。
現在考慮同樣的處理間隔,其中應用已經普及的處理負荷超過兩個GPU:
在一個完美的世界裏,你所期望的2 GPU處理間隔正好一半的單GPU(因爲每個GPU都在做一半的工作)。正如您所看到的,這並非部分原因,因爲由於某種爭用問題,cudaMallocs在同時調用時(有時延長2-3倍)似乎需要更長的時間。我不明白爲什麼需要這樣做,因爲這兩個GPU的內存分配空間是完全獨立的,所以不應該有cudaMalloc上的全系統鎖定 - 每個GPU鎖定會更合理。
爲了證明我的假設,即同時發生的cudaMalloc調用問題,我創建了一個帶有兩個CPU線程(每個GPU)的可笑簡單程序,每個線程多次調用cudaMalloc。我第一次運行這個程序,使得單獨的線程不會在同一時間撥打cudaMalloc:
你看,它需要每〜175分配微秒。接下來,我跑的程序與線程同時調用cudaMalloc:
在這裏,每個呼叫拿了〜538微秒或比以前的情況下,長3倍!毋庸置疑,這大大減緩了我的應用程序的運行速度,而且這意味着只有2個以上的GPU纔會導致問題惡化。
我已經注意到在Linux和Windows上的這種行爲。在Linux上,我使用的是Nvidia驅動程序版本319.60,在Windows上我使用的是327.23版本。我正在使用CUDA工具包5.5。
可能的原因: 我在這些測試中使用GTX 690。這張卡基本上是2 680個像GPU一樣的單元。這是我運行過的唯一的「多GPU」設置,所以或許cudaMalloc問題與690的2個GPU之間的一些硬件依賴有關?
高性能代碼的常見建議是使malloc操作脫離任何性能循環。我意識到這並不是一個微不足道的問題,因爲你使用推力。有高性能的排序庫可以替代推力sort_by_key,這將允許您提前進行分配並將其重新用於排序操作。 [CUB](http://nvlabs.github.io/cub/),[b40c](http://code.google.com/p/back40computing/)和[MGPU](http://nvlabs.github .io/moderngpu /)都是可能的。 –
是的,我已經看過CUB和B40C(B40C網站說該項目已被棄用)。在我做清除推力的工作之前,我想看看圖書館之間的一些比較圖。你能指點我一些表演數字嗎?你推薦哪個圖書館? ......似乎推力並不是非常高的性能,例如,我已經用我自己的定製內核交換了一堆推力:: reduce和reduce_by_key調用 - 這樣做將我的處理時間減半。不是開玩笑。 – rmccabe3701
推力實際上是基於b40c的一個特定變體(或曾經是)。對於等效的測試用例,我在b40c和MGPU之間的測試沒有太大差異。在我運行的一個測試中,我只對32位值的22位進行排序。 MGPU有一個撥號盤,我可以轉而只用22位分辨率,我觀察到這樣做的速度提高了40%。我沒有使用CUB多。如果你瀏覽這些鏈接,你可能會發現一些性能數據。例如,某些MGPU性能數據[here](http://nvlabs.github.io/moderngpu/performance.html#performance) –