無論有沒有共享內存,CUDA內核都可以以任意順序執行的塊(線程塊)執行。要充分利用硬件,您的內核調用中必須有多個線程塊,但這會產生不確定的執行順序。
正因爲如此,掃描算法在大型數組上工作時,必然需要以線程塊大小的塊(以某種方式)工作。如果我們有多個線程塊,那麼給定的線程塊無法知道其他線程塊是否已完成相鄰數據的工作。 (是的,有設計的機制來允許線程間塊通信,但是這些都是困難的並且不能大規模地解決問題。)
這樣的算法通常意味着這樣的算法意味着全球同步的某種類型,唯一的安全在任何情況下的全球同步是內核啓動。線程塊可以獨立完成一部分工作,但是當需要將線程塊的工作拼接在一起時,我們必須等到步驟A在所有線程塊之間完成後再繼續步驟B.
因此,我認爲你會發現大多數設備範圍的掃描算法,包括您鏈接的第39章GPU Gems示例,以及thrust和cub將啓動多個內核來完成此項工作,因爲內核啓動提供了方便的全局同步。
請注意,我們當然可以設計一個掃描,它具有「工作在比每個塊的線程更多的元素上」的獨立線程塊,但這並不能最終解決我們的問題(除非我們只使用1個線程塊),因爲我們必須啓動多個threadblocks充分利用硬件的優勢,並且在一般情況下多個線程塊引入了全局同步的必要性。
我提到的cub和thrust的實現都是開源的模板庫,所以如果你願意,你可以在那裏學習代碼(不是一件小事)。它們確實代表了CUDA專家設計和製造的高質量方法。您也可以在高水平研究他們的行爲很容易使用:
nvprof --print-gpu-trace ./mycode
得到多少內核正在啓動和數據傳輸可能發生什麼快速閱讀,也可以使用nvvp
,視覺分析器,研究這一點。