2012-08-09 139 views
41

什麼時候調用cudaDeviceSynchronize函數真的需要?何時調用cudaDeviceSynchronize?

就我從CUDA文檔中瞭解到,CUDA內核是異步的,所以在每次內核啓動後,我們應該調用cudaDeviceSynchronize。但是,除了時間測量之前,我已經嘗試了使用和不使用cudaDeviceSynchronize的相同代碼(訓練神經網絡)。我發現我得到了相同的結果,但加速度在7-12x之間(取決於矩陣大小)。

所以,問題是如果有任何理由使用cudaDeviceSynchronize除了時間測量。

例如:

  • 需要它從GPU回用cudaMemcpy主機的數據複製之前?

  • 如果我不矩陣乘法像

    C = A * B 
    D = C * F 
    

要我把兩者之間cudaDeviceSynchronize

從我的實驗看來,我沒有。

cudaDeviceSynchronize爲什麼這麼慢?

+0

一個實例是,如果您在內核中有任何打印語句,則直到發生同步事件纔會打印緩衝區。 – 2016-07-08 15:35:45

回答

12

使用cudaDeviceSynchronize()合適的一種情況是,當您有幾個cudaStream s正在運行時,並且您希望讓它們交換一些信息。這種現實生活中的情況是量子蒙特卡洛模擬中的平行回火。在這種情況下,我們希望確保每個流都已經完成了一些指令的運行,並在開始向對方傳遞消息之前獲得了一些結果,否則我們最終會傳遞垃圾信息。使用此命令會導致程序運行速度減慢的原因是,cudaDeviceSynchronize()強制程序在繼續執行之前(來自CUDA C編程指南)等待設備上所有流中先前發出的所有命令完成。正如你所說的,內核執行通常是異步的,因此當GPU設備執行內核時,CPU可以繼續使用其他命令,向設備發出更多指令等等,而不是等待。但是,當您使用此同步命令時,CPU必須閒置,直到所有GPU工作完成,然後再執行其他操作。這種行爲在調試時很有用,因爲由於設備代碼的異步執行(無論是在一個流還是多個流中),您可能會在看似「隨機」時間發生段錯誤。 cudaDeviceSynchronize()會強制程序在繼續之前確保流的內核/ memcpys已完成,這可以更容易地找出非法訪問發生的位置(因爲在同步過程中會出現失敗)。

43

雖然CUDA內核啓動是異步的,但所有與GPU相關的任務放置在一個流中(這是默認行爲)會按順序執行。

因此,例如,

kernel1<<<X,Y>>>(...); // kernel start execution, CPU continues to next statement 
kernel2<<<X,Y>>>(...); // kernel is placed in queue and will start after kernel1 finishes, CPU continues to next statement 
cudaMemcpy(...); // CPU blocks until ememory is copied, memory copy starts only after kernel2 finishes 

所以在您的例子有沒有必要cudaDeviceSynchronize。但是,調試可能會發現哪些內核導致錯誤(如果有)。

cudaDeviceSynchronize可能會導致一些放緩,但7-12x似乎太多了。可能在時間測量方面存在一些問題,或者可能是內核真的很快,並且顯式同步的開銷相對於實際計算時間是巨大的。

+0

除非另有說明,否則「單個默認GPU流」並不總是由nvcc保存。我只是調試了一個程序,在這個程序中,我將一個內核的冗長計算分解爲分段計算,該計算每次在for()循環中啓動一個內核。 ()循環內核啓動的繼續取代了之前for()循環內核離開設備端的地方。錯誤在於nvcc編譯器無法從主機代碼中看到這一點,並試圖同時啓動每個內核。這意味着除了第一個內核之外的所有內核都在計算垃圾。 – opetrenko 2014-07-09 01:47:31

+2

@opetrenko這不是CUDA的工作原理。 – 2014-10-21 21:23:42

+0

@AleksandrDubinsky請仔細閱讀我的評論。我非常明確地寫下「並不總是由nvcc持有」。然後我給出了一個我用cuda-gdb追查的具體bug的例子,它充當了一個證明這一點的例子。我肯定會同意,根據Nvidia的文獻,這不是CUDA應該如何工作......但我所說的並不是一個觀點:它是在調試過程中對某個特定實例的工作方式進行的觀察。 – opetrenko 2015-01-23 19:47:16

3

當您希望GPU開始處理某些數據時,通常會進行內核調用。 當你這樣做時,你的設備(GPU)會開始做你所說的任何事情。但是,與主機上的正常順序程序(CPU)不同,它將繼續執行程序中的下一行代碼。 cudaDeviceSynchronize使主機(CPU)等待設備(GPU)執行完所有已啓動的線程,因此程序將繼續,就像它是一個正常的順序程序一樣。

在小型簡單程序中,當您使用GPU進行計算時,通常會使用cudaDeviceSynchronize,以避免請求結果的CPU與GPU完成計算之間的時序不匹配。使用cudaDeviceSynchronize可以使你的程序編碼變得更容易,但是有一個主要缺點:在GPU進行計算時,CPU一直處於空閒狀態。因此,在高性能計算中,您經常努力讓您的CPU在等待GPU完成時進行計算。