Chart 8 內核優化

文章目錄

  • 前言
  • 8.1 內核融合和拆分
  • 8.2 編譯選項
  • 8.3 Conformant(規范) vs. fast vs. native math functions
  • 8.4 Loop unrolling
  • 8.5 避免分支發散
  • 8.6 Handle image boundaries
  • 8.7 Avoid the use of size_t
  • 8.8 通用 vs. 具名內存地址空間
  • 8.9 Subgroup
  • 8.10 Use of union
  • 8.11 Use of struct
  • 8.12 綜合


前言

這一章節提供了有關內核優化的更多細節,這些內容可能與第6章的頂級優化提示和第7章的內存優化有一些重疊。


8.1 內核融合和拆分

一個復雜的應用可能包含許多階段。對于進行 OpenCL 移植和優化的情況,人們可能會問應該使用多少個內核。這個問題很難回答,因為涉及到許多因素。以下是一些建議:

  • 在內存和計算之間取得良好的平衡。
  • 有足夠的波(waves)來隱藏延遲。
  • 避免寄存器溢出。

開發人員可以嘗試以下操作:

  • 將一個大內核拆分成多個小內核可能會更好地實現數據并行化。
  • 將多個內核融合成一個內核(內核融合),如果可以通過良好的并行化來減少數據流量(工作組大小相當大)。

8.2 編譯選項

APIs clCompileProgram 和 clBuildProgram 提供了許多編譯器構建選項,用于性能優化。借助這些選項,開發人員可以根據其目的啟用一些功能。例如,使用 -cl-fast-relaxed-math 將使用快速數學運算編譯內核,而不是按照 OpenCL 規范提供的更高精度的數學運算:

clBuildProgram( myProgram, numDevices, pDevices, "-cl-fast-relaxed-math ",NULL, NULL );

Adreno GPU 還可以支持一些特定于 Adreno 的選項,以啟用特定功能,詳見第 9 章的討論。

8.3 Conformant(規范) vs. fast vs. native math functions

《OpenCL》標準在OpenCL C語言中定義了許多數學函數。默認情況下,所有的數學函數都必須符合IEEE 754單精度浮點數數學要求,這是OpenCL規范要求的。Adreno GPU具有一個內置的硬件模塊,即基本函數單元(EFU),用于加速一些原始數學函數。EFU直接不支持的許多數學函數已經通過結合EFU和ALU操作進行了優化,或者通過編譯器使用復雜算法進行了模擬。以下表格顯示了基于相對性能對OpenCL-GPU數學函數進行分類的列表。使用高性能函數(例如,類別A中的函數)是一個良好的做法。
在這里插入圖片描述

或者,如果應用程序對精度不敏感,開發人員可以使用本地或快速數學而不是符合規范的數學函數。表8-2總結了使用數學函數的這三個選項:
本地數學函數(native math function),由底層硬件(如GPU)本地支持的數學函數

  • 對于快速數學,在clBuildProgram調用中啟用-cl-fast-relaxed-math。
  • 使用本地數學函數:
    • 具有本地實現的數學函數有 native_cos、native_exp、native_exp2、native_log、native_log2、native_log10、native_powr、native_recip、native_rsqrt、native_sin、native_sqrt、native_tan、native_divide;
    • 以下是使用本地數學的示例:
      • 原始:int c = a / b; // a和b都是整數
      • 使用本地指令:int c = (int)native_divide((float)(a), (float)(b));
        在這里插入圖片描述

8.4 Loop unrolling

循環展開通常是一個良好的實踐,因為它可以減少指令執行成本并提高性能。Adreno編譯器通常可以根據一些啟發式方法自動展開循環。然而,也有可能編譯器選擇不完全展開循環,這取決于諸如寄存器分配預算之類的因素,或者編譯器由于缺乏知識而無法展開。在這些情況下,開發人員可以通過以下方式向編譯器提供提示或手動強制展開循環:

  • 一個內核可以通過使用 attribute((opencl_unroll_hint)) 或 attribute((opencl_unroll_hint(n))) 來提供提示。
  • 或者,一個內核可以使用指令 #pragma unroll 來展開循環。
  • 最后的選擇是手動展開循環。

8.5 避免分支發散

通常情況下,當同一組(wave)中的工作項(work items)按照不同的執行路徑時,GPU的效率并不高。一些工作項可能需要被屏蔽(masked)以適應不同的分支,導致GPU的占用率降低,如下圖所示。此外,條件檢查的代碼,比如if-else,通常會觸發控制流硬件邏輯,這是比較昂貴的操作。
在這里插入圖片描述
有一些方法可以避免或減少分歧和條件檢查。在算法層面上,可以將進入同一分支的工作項分組為一個非分歧的波(wave)。開發者可以將一些簡單的分歧或條件檢查操作轉換為快速的ALU操作。:

  • 第10.3.6節中的一個示例展示了如何將由昂貴的控制流邏輯執行的三元操作轉換為快速的ALU操作。
  • 另一種方法是使用像select這樣的函數,它可能使用快速的ALU操作而不是控制流邏輯。

8.6 Handle image boundaries

許多操作可能訪問圖像邊界之外的像素。為了更好地處理邊界,應考慮以下選項:

  • 如果可能的話,提前對圖像進行填充。
  • 使用具有良好取樣器的圖像對象(紋理引擎會自動處理)。
  • 編寫單獨的內核來處理邊界,或者讓CPU處理邊界像素。

8.7 Avoid the use of size_t

在許多情況下,64位內存地址對于OpenCL內核編譯可能會帶來復雜性,開發者必須謹慎。開發者應避免在內核中將變量定義為size_t類型。對于64位操作系統,內核中定義為size_t的變量可能必須被處理為64位長整型。Adreno GPU必須使用兩個32位寄存器來模擬64位。因此,具有size_t變量需要更多的寄存器資源,這通常會導致性能下降,因為激活的波浪較少,工作組大小較小。因此,開發者應該使用32位或更短的數據類型,而不是size_t。

對于在OpenCL中返回size_t的內置函數,編譯器可能會嘗試根據其知識推導并限制其范圍。例如,get_local_id返回結果為size_t,盡管local_id永遠不會超過32位。在這種情況下,編譯器使用了一個較短的數據類型。然而,通常最好為編譯器提供最佳的數據類型,以獲得更好的寄存器使用和代碼質量。

8.8 通用 vs. 具名內存地址空間

自OpenCL 2.0以來引入了一種稱為通用內存地址空間的特性。在OpenCL 2.0之前,指針必須指定其內存地址空間,比如local、private或global。通用內存允許在內核中不設置指針的地址空間,GPU會在內核執行期間確定實際的地址空間。這一特性使開發人員能夠重用和減少代碼基礎,尤其適用于庫開發等任務。

使用通用內存地址空間可能會帶來性能損失,因為與識別內存空間相關的硬件成本。以下是一些建議關于內存地址空間的使用:

  • 如果事先知道,開發人員應明確指定內存地址空間。這將減少編譯器的歧義,避免GPU硬件識別實際內存空間的成本。
  • 盡量避免工作項使用不同的內存地址空間。對于統一(固定)的情況,編譯器可能能夠提取內存空間并避免硬件識別其內存空間。
  • 準備不同內存地址空間的不同版本代碼。

8.9 Subgroup

OpenCL 2.0引入的新子組函數提供了比工作組更精細的對工作項的控制。一個工作組包含一個或多個子組,而在Adreno GPU中,子組與波(wave)概念對應。與1D/2D/3D工作組相比,子組只有一個維度。與工作組類似,一組函數允許工作項在子組內查詢其本地ID和其他參數。

子組的強大之處在于OpenCL引入了一套豐富的函數,允許子組中的工作項共享數據并在子組內進行各種操作。沒有這個特性,工作項之間的數據共享可能不得不依賴于本地或全局內存,而這通常是昂貴的。

如何實現子組功能取決于硬件供應商。它可以通過硬件加速或通過軟件仿真來實現。在Adreno GPU中,許多子組功能都是通過硬件加速的。

除了核心OpenCL中的子組功能之外,OpenCL 3.0還有關于子組的KHR擴展。在使用這些擴展之前,檢查擴展的可用性是非常重要的。

子組功能大致可以分為兩種類型:規約和洗牌。

  • 規約:Adreno具有硬件支持的規約功能,比通過本地內存進行規約要快得多。
  • 洗牌:洗牌允許數據從一個工作項傳遞到另一個工作項。通常支持shuffle-up, shuffle-down, and generic shuffle.

除了對標準子組函數的支持,Adreno GPU 還通過供應商擴展支持子組規約和洗牌功能。

8.10 Use of union

雖然聯合(union)是 OpenCL 內核語言中的一個標準特性,但在 Adreno GPU 上它是低效的。編譯器需要分配額外的寄存器來處理不同大小的成員,因此性能通常較不使用聯合的常規內核更差。開發者在 Adreno GPU 上應避免使用聯合

8.11 Use of struct

結構體(struct)可以使代碼更易于理解和組織,是將一組相關變量組織到一個地方的絕佳方式。盡管有這些優點,但在 Adreno GPU 上使用結構體可能會引起一些效率問題,因此不總是建議使用。以下是一些建議:

  • 盡量避免在結構體內部使用指針。
  • 明確分配單個成員,而不是將整個結構體變量分配給另一個變量。
  • SoA(struct of array,結構體,元素是數組) 或 AoS(array of struct,數組,元素是結構體):
    • 一個關鍵考慮因素是選擇是否能夠緩解內核的瓶頸。
    • 例如,如果數組可以安排得使得從內存加載數據具有更好的合并性,那么結構體數組是一個更好的選擇。
    • 如果結構體中的成員導致良好的緩存局部性,那么數組結構體可能是一個更好的選擇。

8.12 綜合

許多其他看似細微的優化技巧都可能提高內核性能。以下是開發人員可以嘗試的一些事項:

  • 預先計算在內核中不會改變的值。
    • 使用內核計算可以預先計算的值是不劃算的。
    • 可以通過內核參數或 #define 將預先計算的值傳遞給內核。
    • 使用快速整數內建函數。對于 24 位整數乘法,使用 mul24,對于 24 位整數乘法和累加,使用 mad24。
    • Adreno GPU 在硬件上原生支持 mul24,而 32 位整數乘法則需要多于一條指令。
    • 如果整數在 24 位范圍內,使用 mul24 比直接的 32 位乘法更快。
  • 減少 EFU(elementary function unit) 函數的使用。
    • 例如,以下是一段代碼:
      r = a / select(c, d, b<T)
      
      其中 a、b 和 T 是 float 變量,c 和 d 是常量,可以重寫為:
      r = a * select(1/c, 1/d, b<T)
      
      這樣避免了 reciprocal(倒數) EFU 函數,因為 1/c 和 1/d 可以在編譯時由編譯器推導出。
  • 避免除法運算,尤其是整數除法。
    • 在 Adreno GPU 中,整數除法非常昂貴。
    • 不要使用除法,而是使用 native_recip 進行倒數運算,如第 8.3 節所述。
  • 避免使用整數模運算 (mod,取余),這對 Adreno GPU 來說是昂貴的。
  • 對于常量數組,如查找表、濾波器系數等,將它們聲明在內核范圍之外
  • 在 OpenCL 內核中使用 mem_fence 函數來分隔或組織代碼段。
    • 編譯器具有從全局優化角度生成最佳代碼的復雜算法。
    • mem_fence 可能會阻止編譯器在前后混合代碼之前進行重排
    • mem_fence 允許開發人員操作一些代碼以進行性能分析和調試。
  • 使用16位ALU計算而不是8位。由于Adreno GPU不支持通用的8位ALU操作,8位可能需要轉換為16位或32位ALU操作。
  • 如果可能的話,使用位移操作而不是乘法。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210341.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210341.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210341.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

七個常用<python裝飾器>---足夠改進代碼質量 (保姆詳解)

前言: 寫代碼嘛&#xff0c;關鍵是得讓它既好用又好看&#xff0c;這不&#xff0c;Python裝飾器就擺在那兒。咱們程序員有時也得有那么點藝術家的腔調&#xff1a;講求效率&#xff0c;追求代碼的簡潔優雅&#xff0c;偶爾還得裝裝X&#xff0c;不是嗎&#xff1f; 翻開人家…

SpringSecurity6 | 自定義認證規則

?作者簡介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;熱愛Java后端開發者&#xff0c;一個想要與大家共同進步的男人&#x1f609;&#x1f609; &#x1f34e;個人主頁&#xff1a;Leo的博客 &#x1f49e;當前專欄&#xff1a; Java從入門到精通 ?特色專欄&#xf…

移相干涉技術1-多種干涉條紋仿真模擬生成(原理轉載+代碼實現 包括模擬生成干涉條紋圖)

過去的干涉測量技術是通過人的肉眼或者相機拍攝&#xff0c;來直觀判斷干涉圖中條紋特征進而完成測量&#xff0c;該方法的不穩定因素&#xff08;比如人的主觀意志&#xff09;很多&#xff0c;其精度誤差在/10左右38]&#xff1b;現代干涉測量技術通過將電子技術、計算機技術…

智能優化算法應用:基于廚師算法無線傳感器網絡(WSN)覆蓋優化 - 附代碼

智能優化算法應用&#xff1a;基于廚師算法無線傳感器網絡(WSN)覆蓋優化 - 附代碼 文章目錄 智能優化算法應用&#xff1a;基于廚師算法無線傳感器網絡(WSN)覆蓋優化 - 附代碼1.無線傳感網絡節點模型2.覆蓋數學模型及分析3.廚師算法4.實驗參數設定5.算法結果6.參考文獻7.MATLAB…

代碼隨想錄-刷題第二十一天

530.二叉搜索樹的最小絕對差 題目鏈接&#xff1a;530. 二叉搜索樹的最小絕對差 思路&#xff1a;二叉搜索樹的中序遍歷是有序的。根據二叉搜索樹的這個特性來解題。 class Solution {// 同樣利用二叉樹中序遍歷是一個有序數組。private List<Integer> list new Arra…

一加 12 Pop-up快閃活動來襲,十城聯動火爆開啟

12 月 9 日&#xff0c;一加 12 Pop-up 快閃活動在北京、深圳、上海、廣州等十城聯動開啟&#xff0c;各地加油歡聚快閃現場&#xff0c;搶先體驗與購買一加 12。作為一加十年超越之作&#xff0c;一加 12 全球首發擁有醫療級護眼方案和行業第一 4500nit 峰值亮度的 2K 東方屏、…

C++新經典模板與泛型編程:策略類模板

策略類模板 在前面的博文中&#xff0c;策略類SumPolicy和MinPolicy都是普通的類&#xff0c;其中包含的是一個靜態成員函數模板algorithm()&#xff0c;該函數模板包含兩個類型模板參數。其實&#xff0c;也可以把SumPolicy和MinPolicy類寫成類模板—直接把algorithm()中的兩…

【Linux】無法使用 ifconfig 查看系統網絡接口信息,報錯 command not found: ifconfig

問題描述 ifconfig是一個用于配置和顯示系統網絡接口信息的命令行工具。它通常用于Unix、Linux和其他類Unix系統中。 通過ifconfig命令&#xff0c;你可以查看和修改系統中網絡接口的配置信息&#xff0c;包括IP地址、子網掩碼、MAC地址、MTU&#xff08;最大傳輸單元&#x…

javacv踩坑記錄

前一陣學習opencv&#xff0c;發現在做人臉識別的時候遇到一些類庫不存在的情況&#xff0c;查找后發現是由于拓展包沒有安裝完全&#xff08;僅安裝了基礎版&#xff09;。由于網絡的問題&#xff08;初步猜測&#xff09;&#xff0c;始終無法安裝好拓展包。 于是另辟蹊徑&am…

MongoDb數據庫

一、命令交互 1.1 數據庫命令 1.顯示所有數據庫&#xff1a; show dbs 2.切換到指定數據庫&#xff0c;如果沒有則自動創建數據庫 use databaseName 3.顯示當前所在數據庫 db 4.刪除當前數據庫 use 庫名 db.dropDatabase() 1.2 集合命令 1.創建集合 db.createColl…

[文檔級關系抽取|ACL論文]文檔級關系抽取中語言理解的基礎模型

Did the Models Understand Documents? Benchmarking Models for Language Understanding in Document-Level Relation Extraction School of Computer Science, Fudan University | ACL 2023.06 | 原文鏈接 Background 過去的工作大多數都是從單個句子中收獲更多的關系&am…

MongoDB中的$type操作符和limit與skip方法

本文主要介紹MongoDB中的$type操作符和limit與skip方法。 目錄 MongoDB的$type操作符MongoDB的limit方法MongoDB的skip方法 MongoDB的$type操作符 MongoDB中的$type操作符用于檢查一個字段的類型是否與指定的類型相匹配。它可以用于查詢和投影操作。 $type操作符可以與以下數…

php,redis實現一個電影熱度排行榜

要實現電影熱度排行榜&#xff0c;需要記錄每個電影的熱度值&#xff0c;熱度值可以根據不同的算法計算&#xff0c;例如&#xff1a;觀看次數、評分數、評論數等。這里我們以觀看次數為例。 首先&#xff0c;需要使用 Redis 的 Sorted Set 數據結構來存儲電影的熱度值和電影 …

JVS低代碼表單引擎:數據校驗與處理的先鋒

隨著信息技術的迅速發展&#xff0c;數據校驗與處理已經成為了各類應用中不可或缺的一環。尤其是在涉及敏感信息&#xff0c;如密碼處理時&#xff0c;其安全性和準確性顯得尤為重要。JVS低代碼表單引擎提供了強大的文本組件觸發邏輯校驗功能&#xff0c;它能夠在用戶填寫數據的…

截取字符串

輸入一個字符串和一個整數 k &#xff0c;截取字符串的前k個字符并輸出。 數據范圍&#xff1a;字符串長度滿足 1≤n≤1000&#xff0c; 1≤k≤n 輸入描述&#xff1a; 1.輸入待截取的字符串 2.輸入一個正整數k&#xff0c;代表截取的長度 輸出描述&#xff1a;截取后的字符串…

模電·放大電路的分析方法——等效電路法

放大電路的分析方法——等效電路法 晶體管的直流模型及靜態工作點的估算法晶體管共射h參數等效模型 h h h參數等效模型的由來參數的物理意義簡化的h參數等效模型 r b e {r\tiny be} rbe的近似表達式 共射放大電路動態參數的分析電壓放大倍數 A ˙ u \.{A}\tiny u A˙u輸入電阻 …

三種配置Spring程序的方法

1 使用XML文件配置Spring程序 在XML文件中使用bean標簽&#xff0c;將其交給容器管理 class: 指定bean對應的類型的全限定名稱id: 用于指定一個名稱&#xff0c;作為該bean的唯一標識符&#xff0c;如果不需要id&#xff0c;也可不指定該屬性name: 用于指定bean的別名&#x…

【小米電腦管家】安裝使用教程--非小米電腦

安裝說明功能體驗下載資源 Xiaomi HyperOS發布后&#xff0c;小米妙享電腦端獨立版本也走向終點&#xff0c;最新的【小米電腦管家】將會內置妙享實現萬物互聯。那么本篇文章將分享非小米電腦用戶如何繞過設備識別驗證安裝使用【小米電腦管家】實現萬物互聯 安裝說明 1.解壓文…

如何用Python編寫俄羅斯方塊Tetris游戲?

在本文中&#xff0c;我們將用Python代碼構建一個令人驚嘆的項目&#xff1a;俄羅斯方塊游戲。在這個項目中&#xff0c;我們將使用pygame庫來構建游戲。要創建此項目&#xff0c;請確保您的系統中安裝了最新版本的Python。讓我們開始吧&#xff01; Pygame是一組跨平臺的Pyth…

wireshark過濾包小技巧

1、過濾包含某個字符串的數據包&#xff1a; 或者&#xff1a; 2、過濾包含某一連續十六進制的數據包&#xff1a; 或者&#xff1a; 3、過濾精確到位數位置 或者&#xff1a;