2015-07-20 32 views
1

我有一個應用程序,我設計用OpenCL在AMD GPU上運行。終於讓應用程序運行並且沒有bug(哈哈),它只針對一個GPU。現在,該應用程序的作品,是時候擴展到多個GPU。使用多個GPU時OpenCL內核START延遲?

閱讀了解如何設置它。我們使用單個上下文,多個隊列方法。

我拉出設備列表,並選擇2個GPU並創建一個包含它們的上下文,然後包含這兩個設備的單個BuildProgram。創建兩個單獨的隊列。

原來,工作程序的僞代碼,現在轉換處理2個GPU:

context = clCreateContext(0, 2, device_list, NULL, NULL, &ret); 
for(x = 0; x < 2; x++) 
    queue[x] = clCreateCommandQueue(context, device_list[x], ENABLE_PROFILING, &ret); 
clBuildProgram(program, 2, device_list, options, NULL, NULL); 

create kernels.. 

run... 
for(outer_loop = 0; outer_loop < 10; outer_loop++) { 
    clEnqueueNDRangeKernel(queue[0], kernel_init, offset, &event[0]); 
    clEnqueueNDRangeKernel(queue[1], kernel_init, different_offset, &event[1]); 
    clFinish(queue[0]); 
    clFinish(queue[1]); 

    get profiling data and printf results 
} 

那基本上如何代碼看起來。參數被設置並且寫入在循環之前完成 - init內核不依賴於輸入來開始工作。運行後,它會將其生成的數據的async_work_group_copy做爲全局緩衝區。現在

,之前我修改了代碼爲2個GPU,內核在27ms跑(每個循環)

後,我修改了代碼,如果我註釋掉一個或另一個的2點內核運行的(在EnqueueNDRangeKernel和關聯的clFinish),它們都將以27ms運行。

如果我運行代碼並行運行在兩個GPU上,我會遇到非常奇怪的行爲。

循環中的第一次運行,它們都以大約37-42ms單獨執行。我可以輕微放緩,因爲我已經完成了兩次工作。但是在第一次運行之後,其中一個或另一個內核將在排隊和啓動之間隨機地有4-5秒的延遲。

下面是我的分析/計時輸出。所有數字均以毫秒爲單位。

Q0: til sub: 8.8542 til start: 9.8594 til fin: 47.3749 
Q1: til sub: 0.0132 til start: 13.4089 til fin: 39.2364 

Q0: til sub: 0.0072 til start: 0.2310 til fin: 37.1187 
Q1: til sub: 0.0122 til start: 4152.4638 til fin: 4727.1146 

Q0: til sub: 0.0302 til start: 488.6218 til fin: 5049.7233 
Q1: til sub: 0.0179 til start: 5023.9310 til fin: 5049.7762 

Q0: til sub: 0.0190 til start: 2.0987 til fin: 39.4356 
Q1: til sub: 0.0164 til start: 3996.2654 til fin: 4571.5866 

Q0: til sub: 0.0284 til start: 488.5751 til fin: 5046.3555 
Q1: til sub: 0.0176 til start: 5020.5919 til fin: 5046.4382 

我正在運行這臺機器上有5個GPU。無論我使用哪兩個,兩個GPU中的一個(不總是相同的)在啓動時會延遲4-5秒。使用單個GPU - 無延遲。

這可能是什麼原因造成的?任何想法?我沒有阻止 - clFinish只是獲取性能分析信息。即使它阻止了它也不會是5秒的延遲。

另外 - 我想也許是全球範圍內寫入內核的行爲可能是延遲的一部分。我評論寫道。不。不用找了。

其實我加了一個return;作爲內核的第一行 - 所以它完全沒有。 40毫秒下降到0.25,但5秒延遲仍然存在。

+0

您是否嘗試過在CodeXL中運行所有這些?您可以獲得所發生事件的時間表(數據傳輸,API調用,內核執行等)。不幸的是,使用正確的工具可以找出更好的機會,而不是我們用這種有限的信息搞清楚。 –

+0

只是可以肯定的(我認爲這是其他地方的解決方案),我剛剛升級到最新的AMD驅動程序並與OpenCL庫匹配。不用找了。存在相同的延遲。 – InfernusDoleo

+0

不,我還沒有使用過CodeXL。不幸的是,我不在圖形環境中,試圖查找,閱讀和理解如何使用命令行版本似乎比首先學習OpenCL更困難。如果一切都失敗了,我會試試這條路線。 – InfernusDoleo

回答

2

OpenCL驅動程序不關心內核中發生了什麼。如果內核寫/讀或者是一個空內核,或者它只寫入緩衝區的一部分。它關心緩衝區參數標記,並確保跨GPU的數據是一致的,如果它們在其他內核中具有任何依賴關係,則會阻止內核。 GPU到GPU的傳輸透明地發生,並且可能非常昂貴。

當使用多個GPU時,隱藏的數據複製和同步必須認真對待,因爲這通常是主要瓶頸。

如果你的內核可以並行運行(因爲GPU1工作在GPU2上的不同數據,等等......),那麼你應該爲每個GPU創建不同的緩衝區。或者如果數據相同,請正確設置類型CL_READ_ONLY/CL_WRITE_ONLY,以確保正確的OpenCL行爲。和最小的複製/一致性操作。


例如,對於這些內核:

kernel Sum(read_only A, read_only B, write_only C); 
kernel Sum_bad(read_write A, read_write B, write_only C); 

如果使用單GPU,兩者的行爲完全一樣的,因爲所有的內存駐留在同一GPU。 但是,使用多GPU可能會導致可怕的問題,例如:

Queue 1/GPU 1: Sum_Bad(A,B,C); 
Queue 2/GPU 2: Sum_Bad(A,D,E); 

將發生如下事件:

  1. 記憶A,B將被複制到GPU1內存(如果它已經不存在)。在GPU1中分配的C內存。
  2. GPU 1將運行內核。
  3. 內存A將從GPU1複製到GPU2。內存D將被複制到GPU2。內存E分配。
  4. GPU2將運行內核。

正如您所看到的,GPU2必須等待第一個完成,並等待所有參數複製回來。 (可以說是5秒,也許,這取決於大小?)


然而,使用正確的方法:

Queue 1/GPU 1: Sum(A,B,C); 
Queue 2/GPU 2: Sum(A,D,E); 

的事件將發生如下:

  1. 記憶A,B將被複制到GPU1內存(如果它不在那裏)。在GPU1中分配的C內存。
  2. GPU 1將運行內核。

在平行(因爲沒有扶養)

  1. 存儲器A,d將被複制到GPU2(如果它不存在的話)。內存E分配。
  2. GPU2將運行內核。
+0

現在修改代碼以擁有單獨的緩衝區,但同時,即使內核沒有做任何事情,這個複製/延遲問題也會出現嗎?它只是返回?僅僅在循環開始之前將數據寫入一次 - 它會繼續嗎? – InfernusDoleo

+0

另外 - 看來我需要2個不同的上下文有2個不同的緩衝區?正確? – InfernusDoleo

+0

關於gpu到gpu的傳輸成本高昂 - 5秒?在gpus之間移動805兆數據?我可以在主機端以毫秒爲單位讀取,阻止,寫入和阻止。如果我經歷了80毫秒的延遲 - 好的 - 我會給你的。但5000?我目前正在重新編寫代碼以基本複製所有內容,並有2個上下文。我會報告一旦它停止在setKernelArg上進行segfaulting會發生什麼。 – InfernusDoleo