OpenCL 通用程式設計與優化(6)
- 5. 性能優化的概述
-
- 5.1性能可移植性
- 5.2最優化的進階視圖
- 5.3對OpenCL移植的初步評估
- 5.4端口CPU代碼到OpenCL GPU
- 5.5并行化GPU和CPU的工作負載
- 5.6瓶頸分析
-
- 5.6.1識别瓶頸
- 5.6.2解決瓶頸
- 5.7 API級性能優化
-
- 5.7.1API函數調用的正确安排
- 5.7.2使用事件驅動的管道
- 5.7.3核心的編譯和建構
- 5.7.4二進制核心的向後相容性
- 5.7.5使用順序指令隊列
5. 性能優化的概述
本章提供了對OpenCL應用程式優化的進階概述。更多細節在下面的幾章。
對OpenCL應用程式的優化可能具有挑戰性。它通常需要比最初的開發更多的努力。
5.1性能可移植性
正如在第2.4.2節中所讨論的,OpenCL的性能在很大程度上依賴于硬體平台的底層體系結構,并且通常不能在不同的體系結構之間進行可移植。在其他平台上優化的OpenCL應用程式,特别是在離散gpu上,不太可能在移動gpu上表現良好。是以,其他OpenCL供應商的最佳實踐可能不适用于Adrenogpu。閱讀這整個文檔對Adrenogpu的優化工作是至關重要的。此外,為Adreno GPU優化的OpenCL應用程式可能需要進一步的調優和優化,以實作在其他Adreno GPU上的最佳性能。
性能、生産力和可移植性通常是開發人員需要平衡的三件事。很難同時實作這三個目标,因為它們取決于時間、預算和目标。例如,更好的可移植性需要更多的通用代碼,因為一些特定的優化提示可能隻适用于某些gpu。類似地,要實作更好的生産力,即能夠快速開發、優化和部署應用程式,通常需要在性能或可移植性方面的犧牲。開發人員必須根據其優先級和目标做出仔細的決策。
5.2最優化的進階視圖
對OpenCL應用程式的優化可以從上到下大緻分為以下三個級别:
- Application/algorithm.
- API函數。
-
核心優化。
OpenCL優化問題本質上是一個如何優化利用記憶體帶寬和計算能力的問題,包括:
- 使用全局記憶體、本地記憶體、寄存器、緩存等的最佳方法。
-
利用計算資源的最佳方法,如ALU和紋理操作。
應用程式級的優化政策在本章的其餘部分中,而其他級别則在以下章節中。
5.3對OpenCL移植的初步評估
開發人員必須評估一個應用程式對OpenCL是否合适,然後才能盲目地移植它。以下是在gpu上進行OpenCL加速的良好候選者的典型特征:
- 廣泛的輸入資料集。
- 對于小的輸入資料集,cpu和gpu之間的通信開銷可能會掩蓋OpenCL的性能增益。
- 計算密集型。
- gpu有許多計算單元(alu),它們的峰值計算能力通常比cpu高得多。為了充分利用GPU,應用程式應該具有相當高的計算複雜度。
- 并行計算友好。
- 一個工作負載可以被劃分為小的獨立單元,每個單元的處理不影響其他單元-。
- gpu需要并行化的任務來隐藏延遲。
- 有限的發散控制流。
- gpu通常不能像cpu那樣有效地處理發散性控制流。如果用例需要大量的條件檢查和分支操作,那麼cpu可能更合适。
5.4端口CPU代碼到OpenCL GPU
通常,開發人員可能已經有了一個基于cpu的引用程式,用于OpenCL移植。假設該程式由許多小的功能子產品組成。雖然在逐個映射的基礎上将每個子產品轉換為OpenCL核心似乎很友善,但性能不太可能是最優的。必須考慮以下因素:
- 在某些情況下,将多個CPU功能子產品合并到一個OpenCL核心中,如果這樣做會減少GPU和記憶體之間的資料流量,則會帶來更好的性能。
- 在某些情況下,将一個複雜的CPU功能子產品分割為多個更簡單的OpenCL核心可以産生更好的單個核心的并行化和更好的整體性能。
- 開發人員可能需要修改資料結構來調整資料流并減少總體流量。
5.5并行化GPU和CPU的工作負載
為了充分利用SOC的計算能力,應用程式可以在GPU執行核心時将一些任務委托給CPU。在設計這樣的拓撲和配置設定工作負載時,這裡需要考慮以下幾點:
- 讓CPU執行最适合CPU的部分,如發散控制流和順序操作。
- 避免出現GPU空閑并等待CPU完成的情況,反之亦然。
- 如果CPU和GPU之間需要大量的同步或資料傳輸,那麼它們之間的資料共享可能會很昂貴。相反,嘗試将輕量級的CPU任務轉移到GPU上,即使它可能對GPU不友好,以消除開銷。
5.6瓶頸分析
瓶頸是開發人員應該花最多時間去關注的最慢的階段。無論所有其他階段的效率有多高,一個應用程式的性能都會受到其瓶頸的限制。識别和分析瓶頸是至關重要的,而且并不總是那麼簡單。本節将簡要讨論識别和解決瓶頸。
5.6.1識别瓶頸
通常,核心要麼是記憶體綁定的,要麼是計算綁定的(也稱為ALU綁定)。一個簡單的技巧是操作核心代碼,并在一個裝置上運作核心如下:
- 如果添加更多的計算不會改變性能,那麼它可能不是有計算邊界的。
-
如果過多的資料加載不會改變性能,則它可能不是記憶體綁定的。
如第4.3節所述,可以使用骁龍分析儀用于識别瓶頸。
5.6.2解決瓶頸
一旦确定了瓶頸,就可以使用不同的政策來解決它。
- 如果這是一個基于alu邊界的問題,請找到降低複雜性和計算量的方法。
- 使用快速放松的數學或本機數學。
- 使用16位浮點格式,而不是32位浮點格式。
- 如果這是一個記憶體綁定的問題,嘗試改進記憶體通路,如向量負載/存儲,利用本地記憶體或紋理緩存(例如,使用隻讀高通®骁龍™移動平台OpenCL一般程式設計和優化性能優化概述80-NB295-11 Rev。B可能包含美國和國際出口控制資訊38個圖像對象代替緩沖對象)。使用較短的資料類型在GPU和全局記憶體之間加載/存儲資料,有利于節省記憶體流量。
-
詳情将在以下章節中進行描述。
注意:瓶頸可能會随着優化的進展而改變。在解決了記憶體瓶頸後,記憶體綁定問題可能會變成alu綁定問題,反之亦然。為了獲得最優性能,需要進行多次來回疊代。此外,瓶頸問題也可能會有所不同
-
5.7 API級性能優化
OpenCL API用于管理資源和控制應用程式的執行,主要運作在CPU主機上。盡管這些函數不像核心執行那樣要求很高,但不當使用API函數可能會導緻嚴重的性能損失。以下是可以幫助開發人員避免一些常見陷阱的幾點。
5.7.1API函數調用的正确安排
昂貴的API函數應該被正确地放置,以便它們不會阻止或影響對GPU的工作負載的啟動。一些OpenCL API函數需要很長時間,應該在執行循環之外調用。例如,以下函數可能需要相當長的時間:
clCreateProgramWithSource()
clBuildProgram()
clLinkProgram()
clUnloadPlatformCompiler()
-
要減少應用程式啟動期間的執行時間,請使用“建立二進制程式”而不是“建立程式”。詳見第5.7.3節。
當克隆建立二進制程式失敗時,不要忘記從源代碼傳回到建構。但是,如果OpenCL軟體有不相容的更新,就可能發生這種情況。
- 避免在核心調用之間建立或釋放記憶體對象。clCreate{圖像|緩沖區}的執行時間與請求的記憶體量有關(如果使用host_ptr)。
- 如果可能,使用安卓ION記憶體配置設定器。cl建立{緩沖區|圖像2D}可以使用ION指針建立記憶體對象,而不是配置設定額外的記憶體并複制它。第7.4節讨論了如何使用ION記憶體。
- 嘗試在OpenCL中重用記憶體和上下文對象,以避免建立新的對象。主機應該在GPU核心啟動期間做輕量級的工作,以避免阻止GPU的執行。
5.7.2使用事件驅動的管道
OpenCL排隊API函數可以接受一個事件清單,該清單指定在目前API函數開始執行之前必須完成的所有事件。同時,排隊的API函數也可以發出一個事件ID來辨別它們自己。主機隻需将API函數和核心送出給GPU進行執行,而不必擔心它們的依賴性和完整性。使用這種方法大大降低了啟動API函數調用的開銷。該軟體可以最好地排程功能,并且主機不必幹擾API函數調用。是以,我們非常希望使用事件驅動的管道來簡化API函數。此外,開發人員應該注意以下幾點:
- 避免阻塞API調用。阻塞調用需要主機CPU等待GPU完成,然後在下一次克隆遠端核心調用之前停止GPU。阻塞API調用主要用于調試。
- 使用回調函數。從OpenCL 1.2開始,許多API函數都被增強或修改,以接受使用者定義的回調函數來處理事件。這種異步
5.7.3核心的編譯和建構
在運作時編譯和建構核心源代碼可能會很昂貴。一些應用程式可能會實時生成源代碼,因為一些參數可能預先不可用。如果源代碼的建立和編譯不影響GPU的執行,這可能也沒關系。
但通常,不建議進行動态源代碼生成。更好的方法是離線建立源代碼并隻使用二進制核心,而不是實時建構源代碼。在加載應用程式時,也會加載二進制核心代碼。這樣做将顯著減少從磁盤加載代碼的開銷。
5.7.4二進制核心的向後相容性
如果應用程式針對Adreno裝置的不同層,則需要不同版本的二進制代碼。
- 二進制代碼隻能用于要編譯它的特定GPU。例如,為Adreno A730 GPU編譯的二進制檔案不能用于Adreno A740 GPU。
- 不能保證對于同一個裝置,從一個版本的OpenCL軟體建構的二進制檔案可以與較新版本的OpenCL軟體直接重用。
- 如果二進制核心不相容,請使用c建立程式源作為備用解決方案。
5.7.5使用順序指令隊列
Adreno OpenCL平台支援無序的指令隊列。但是,由于實作無序指令隊列需要依賴管理,存在巨大的開銷。Adreno軟體有效地為順序隊列的指令。是以,使用有序指令隊列而不是無序指令隊列是一種很好的做法。