天天看點

OpenCL 通用程式設計與優化(6)5. 性能優化的概述

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。類似地,要實作更好的生産力,即能夠快速開發、優化和部署應用程式,通常需要在性能或可移植性方面的犧牲。開發人員必須根據其優先級和目标做出仔細的決策。

OpenCL 通用程式設計與優化(6)5. 性能優化的概述

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軟體有效地為順序隊列的指令。是以,使用有序指令隊列而不是無序指令隊列是一種很好的做法。

繼續閱讀