高效能計算 (High performance computing,HPC) 作為計算機經典學科分支之一,圍繞計算機體系結構、並行演算法設計與軟體開發,為航天、國防、氣象預報、石油勘探等科研領域,持續提供各類高效能計算裝置乃至超算系統上的科學計算支撐。

而在傳統科學計算領域之外,隨著深度學習的崛起,人工智慧行業對算力的需求正在以指數級增長。近期十分火熱的大模型,甚至達到了成千上萬億級別的引數量[1]。

在此背景下,為了充分發揮計算裝置效能,滿足天文數字般的計算量需求,高效支援深度學習模型生產與部署,高效能計算與深度學習領域之間產生了必然而深刻的聯絡。

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

新的天地 —— HPC@AI

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

基於高效能計算學科背景,面向深度學習雲端推理部署,我們開源了 OpenPPL 高效能推理平臺,致力於從 HPC 視角探索 AI 計算最佳化,推動 AI 應用的廣泛落地。

本文作為 OpenPPL 效能最佳化技術探討的開篇,主要分享通用計算架構下的效能最佳化方法與思考。

本文將從以下三個方面進行「揭秘」:

硬體架構特性分析

基於 Arithmetic Intensity,探索最佳化方向

基於微架構的指令集調優

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

工欲善其事,必先 Benchmark:硬體架構特性分析

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

常言道:知己知彼,百戰不殆。在模型部署階段,攻城獅需要「知己」—— 掌握模型資訊,也需要「知彼」—— 獲取部署平臺的硬體資訊。

然而,在 AI 硬體百花齊放的時代,那份不一定能獲取到的硬體 spec 文件,可能是模型部署人員對目標架構認知的唯一資訊來源。因此 ,對硬體架構的不充分認知,常常成了 AI 模型部署最佳化的攔路虎。

為了從軟體開發視角更加充分地獲取架構引數、理解架構特性,針對目標架構的 micro-benchmark 常常是開啟效能最佳化的第一步。

根據測試目標單元或元件的功能差異,micro-benchmark 可以大體分為

計算相關、訪存相關、通訊相關。

例如,

在計算方面,

可以基於指令相關性,構建指令依賴序列進行指令延遲的 micro-benchmark;可以基於遞增獨立指令流[2]數,進行指令吞吐測試;亦可靈活混合指令依賴與獨立指令流,從而進一步分析指令排程邏輯。

在訪存方面,

可以透過調整 stream benchmark[3] 的 data set 大小,逐級測試各級 cache 直至 Device Memory 的訪存頻寬;可以透過調整 pointer chasing[4] 的 stride,逐級測試各級 cache 直至 Device Memory 的訪存延遲;亦可透過前述兩者測試,交叉驗證各級 cache size。

在通訊方面,

可以透過經典 ping-pong test 獲取點對點通訊開銷;亦可在掌握同步操作特性與開銷的前提下,靈活增加同步操作,進而測試各類單向、多級路由等通訊方式的延遲/頻寬。

透過 micro-benchmark,也可能發現一些有趣的硬體特性:

比如某國產 CPU 裁減了原始 IP 一半的浮點 mul&add 單元;某 DSP scalar core 對 L1 port 的競爭導致多核效能下降(下一代 mac 單元 bypass L1);某國產眾核架構的核間暫存器通訊每隔三次發射產生一個額外 cycle 的 penalty 等等。

這些與底層程式碼調優相關的微架構特性,常常直接影響效能上限,成為效能最佳化的潛在殺手。

除了最佳化前的架構特性分析,實際上在最佳化過程中,面對與預期存在差異的效能表現時,也可以透過最小化復現場景,構建 micro-benchmark 的方式進行微架構層面性能干擾的分析/驗證,從而調整最佳化策略。

AI 中的 AI:基於 Arithmetic Intensity,探索最佳化方向

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

計算效能最佳化,本質上是基於給定的計算模式,在目標硬體平臺上,依據架構特性,尋找最優的計算、訪存、通訊行為的執行序列,從而獲取高效能實現。

可見,計算模式、架構特性、並行演算法設計三者共同影響了效能表現。

因此,基於 micro-benchmark 獲取的硬體架構特性,若能結合計算模式,對效能進行量化分析和建模,則對並行演算法設計、最佳化迭代有重要指導意義。

為定量分析計算模式、硬體架構、效能三者的關係,從而指導並行演算法設計與最佳化方向,我們需要一些量化指標用於輔助分析。

為描述計算與訪存的關聯性,可以使用計算強度 (Arithmetic Intensity [5]) 進行衡量,其含義是在某段計算邏輯下,每搬運單位位元組資料,需要進行的計算次數,也即 Flops Per Byte。

計算強度一定程度上刻畫了計算流程與硬體平臺在計算與訪存方面的特性。而計算模式作為計算/訪存的需求方,硬體平臺作為計算/訪存的資源提供方,兩者的供需關係決定了效能的表現。

為了將硬體平臺與計算模式之間計算和訪存的匹配程度以及需求瓶頸進行量化地展示與分析,可以使用 Roofline Model [6] 進行刻畫。其中縱軸代表可達到的效能上限 (Attainable FLOPS),橫軸為計算強度,斜率為記憶體頻寬,效能與理論峰值取最小值。具體關係式如下:

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

隨著計算強度提升,結合硬體儲存頻寬、計算能力之間的制約關係,我們可以在二維影象中刻畫出一條折線。折線上的每一點標明瞭在當前計算強度(橫軸座標)下,在當前硬體平臺上的理論效能上限(縱軸座標),如圖 1。

其拐點處的計算強度稱之為機器平衡點 (Machine Balance)。

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

圖 1:Roofline Model 簡介示意圖

對於 ARM 移動端單核而言,該數值基本在 10 以下;對於 x86 server 多核而言,該數值可以達到數十甚至上百;對於 server 端 GPU 而言,該數值常常處於數百量級。

若當計算模式對應的計算強度高於機器平衡點,則該計算模式屬於 compute-bound 型別;反之屬於 memory-bound。因此,同樣的計算模式對於不同的架構而言,可能受限於不同因素;對於 MAI 越高的架構,原本 compute-bound 的卷積 case,也可能成為 memory-bound,其效率最佳化到接近峰值的難度也就越大。

另外,多執行緒、SIMD、FMA 開啟情況,以及資料所在儲存層次等因素直接影響了效能上限,我們需要根據具體場景,選擇對應的硬體理論算力與儲存頻寬,對當前硬體平臺進行 Roofline 簡易建模。

為分析硬體與計算任務效能關係,基於上述的硬體 Roofline Model,我們還需要根據當前計算任務的實現方式、計算流程的資料讀寫量和計算量,進行計算強度估算,從而在 Roofline Model 中找到對應的理論效能上限。

需要注意的是,在 roofline model 中,隱含了計算與訪存可以 overlap,以及計算指令序列達到 fully pipelined 等前置條件。另外,若計算過程存在對資料的顯著複用(例如以記憶體頻寬進行 Roofline Model 建模,但大量資料在 Cache 中存在複用),則需要釐清實際訪存量,才能正確估算計算強度。

下圖展示了基於某國產眾核架構(以及某海外硬體廠商的眾核架構)[7] 刻畫的 Roofline Model,以及在此架構下,經典科學計算核心的典型計算強度和預期效能瓶頸。

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

圖 2:某硬體架構下的 Roofline Model 與相關 kernel 計算強度

基於上述完整的 Roofline Model,若根據當前計算流程估算的計算強度顯著低於該類計算模式的理論計算強度(例如幾乎沒有資料複用的 naïve gemm 實現;或者在不同 MNK 引數下,採用了不同的 gemm 外積/內積外圍演算法),則需要進一步更換/改進並行演算法,提升計算強度。

若估算的計算強度已經較優,則需要根據實際效能表現與估算上限的差距,透過 profiling 分析頻寬/計算核心是否處於預期狀態、計算訪存重疊情況等問題,改善計算流程的實際計算強度,從而逼近效能上限。

鬥榫合縫:基於微架構的指令級調優

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

對於 compute-bound 型別的計算任務(比如在算力較低但頻寬相對充裕的邊緣側裝置上的計算密集型任務),核心部分的計算序列是效能熱點,而這部分程式碼的最佳化與微架構特性息息相關,例如流水線上的指令延遲、吞吐、發射邏輯等。

如果將流水線的每一週期、每一階段比作「卯眼」,那麼我們的目的就是將指令序列作為「榫頭」,精準地嵌入到流水線上合適的時鐘週期,從而使整體結構更加緊湊、高效。

通常來說,指令級調優的目標是最大化指令吞吐(甚至達到 fully pipelined),並儘可能減小單次迭代延遲。

除了編譯器排程與硬體亂序支援之外,底層指令手工調優思路包括但不限於以下幾類:

1。 最大化指令對暫存器的複用,提升資料複用率(例如提升分塊大小,從而增大基於 Cache 的計算強度,乃至基於 memory 的計算強度)

2。 依據指令延遲,以及指令間依賴關係,交錯指令發射時機,減少氣泡

3。 暫存器雙緩衝/分時複用,隱藏迭代間的資料載入開銷

4。 依據指令發射埠數量和發射限制,group 相關指令(尤其是 VLIW 類架構)

5。 進行 loop unrolling,尋找上述指令排程最佳化機會,提升 ILP

6。 以軟體模擬演算法替代 SFU 運算(在 SFU 的 IPC 較低的情況下),並輔以 loop unrolling 等等。

在指令級調優過程中,也可以基於計算指令序列,片上儲存頻寬以及架構理論峰值構建 Roofline Model 進行效能瓶頸分析,同時依據 micro-benchmark 反饋的微架構特性,調整建模過程中的架構引數,實現更細緻的調優。

總之,透過對流水線行為、計算序列的準確理解和分析,有助於更加精準地排程和最佳化指令編排,減少時鐘週期的浪費,實現「鬥榫合縫」。

總結

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

本文簡要分享了面向通用計算架構的部分底層效能調優方法與思考:

1。 從硬體 micro-benchmark 著手,獲取架構資訊;

2。 結合計算模式、架構特性,進行效能建模分析與並行演算法設計與改良;

3。 面向計算密集任務,結合微架構特性進行指令級調優。

其簡要邏輯關係如下圖所示,綠色箭頭所指的迴圈過程(效能建模與瓶頸分析←→並行演算法改進,並輔助必要的 micro-benchmark 分析)是最佳化過程的重點。

OpenPPL 高效能推理引擎技術探討:效能最佳化概要

圖 3:最佳化流程示意圖

需要指出的是,隨著演算法模型的演進,更加複雜的訪存密集型運算元也在不斷出現,例如稀疏化、不規則形狀等情況;另一方面,隨著加速器架構演進,計算與頻寬能力的失衡逐步放大,模型的計算瓶頸也加快向訪存密集型靠攏,限於篇幅,暫不在此展開。

最後,歡迎業界感興趣的同學嘗試 OpenPPL 在各類服務端架構上的 CV/NN 部署方案,並提出寶貴建議與意見,共同推動前沿 AI 技術在產業界的落地。

關注我們的開源專案:

交流 QQ 群:627853444,入群密令 OpenPPL