開源神器MegPeak——讓你更懂你的處理器!
2022-06-08 11:17:21 EETOPMegPeak 介紹
在這個算力需求爆炸的大背景下,如何發揮出已有硬件的最大算力變得非常重要,直觀一點是:我們需要對現有算法針對特定的處理器進行極致的性能優化,盡量滿足目前 AI 算法對算力高要求。為了能夠做到極致的性能優化,我們可能的方向有:
優化算法,使得算法能夠在滿足準確度前提下,訪存和計算量盡量小
優化程序,使得實現這些算法的程序最大限度發揮處理器性能
在優化程序的過程中,首先要解決的問題是:如何評估我們程序發揮了處理器幾成的算力,以及進一步優化空間和優化方向。
指令的峰值帶寬
指令延遲
內存峰值帶寬
任意指令組合峰值帶寬
測試 ArmV8 上通用指令峰值和延遲,編譯完成之后,在目標處理器上執行 megpeak,得到:
如上圖所示,MegPeak 可以精確測試出 CPU 上每條指令的計算峰值以及延遲周期。OpenCL 上將測試出不同數據類型進行訪存的 Local Memory,Global Memory 的帶寬,以及 int/float 不同數據類型進行計算的峰值。這些數值將有效的指導我們評估目前程序的性能,并繪制 RoofLine,將可以幫助用戶診斷出阻塞程序主要因素,是訪存或者計算,具體使用分析方法將在后面介紹。
MegPeak 原理
MegPeak 測試的主要參數是
CPU 不同指令的計算峰值,以及指令延遲,以及內存帶寬
OpenCL 中不同內存的數據訪存帶寬,以及不同計算數據類型的計算峰值
但是,流水線在實際執行時候不可能一直這樣流暢的執行下去,會存在以下的冒險,阻塞流水線。
結構冒險——如果硬件無法同時支持指令的所有可能組合方式,就會出現資源沖突,從而導致結構冒險
數據冒險——流水線指令存在先后順序,如果一條指令取決于先前指令的結果,就可能導致數據冒險
控制冒險——分支指令及其他改變程序計數器的指令實現流水化時,可能導致控制冒險
為了測量處理器上一條指令的計算峰值,我們需要寫出重復執行這條指令,但是沒有任何冒險的代碼,所以需要代碼控制數據冒險和控制冒險。
消除數據冒險----消除重復指令之間的數據依賴,讓前后指令之間沒有下面的數據相關,雖然 WAW,WRA 不是真正的數據相關,處理器可能會使用寄存器重命名來解決,但是我們還是盡量不要寫出這樣的數據相關。
寫后讀(RAW):上一條指令寫入,下一條指令讀取寫入數據,這時候后一條指令需要等上一條指令運行結束之后再運行
寫后寫(WAW):兩條指令前后寫入同一個寄存器,這時候數據寫入的先后順序很重要
讀后寫(WRA) :上一條指令讀取一個寄存器,下一條指令將新的數據寫入這個寄存器,他們的順序也同樣很重要
盡可能的消除控制冒險----為了重復多次執行同一條指令,我們可能會用循環來實現,但是循環里面有分支,可能會造成控制冒險,所以我們需要盡可能的循環展開,讓一個循環里面執行更多的數據無關的指令,但是這個數量會被處理器的寄存器數量限制。
下面是 MegPeak 測試 Arm64 上 fmla 指令計算峰值時候的核心 Code。
static int fmla_throughput() {
asm volatile(
"eor v0.16b, v0.16b, v0.16b\n"
"eor v1.16b, v1.16b, v1.16b\n"
...
"eor v19.16b, v19.16b, v19.16b\n"
"mov x0, #0\n"
"1:\n"
"fmla v0.4s, v0.4s, v0.4s\n"
"fmla v1.4s, v1.4s, v1.4s\n"
...
"fmla v19.4s, v19.4s, v19.4s\n"
"add x0, x0, #1 \n"
"cmp x0, %x[RUNS] \n"
"blt 1b \n"
:
: [RUNS] "r"(megpeak::RUNS)
: "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13",
"v14", "v15", "v16", "v17", "v18", "v19", "x0");
return megpeak::RUNS * 20;
}
上面的內嵌匯編代碼中,主要做了幾件事情:
初始化 0–19 號 neon 寄存器為零,這一步不是必須的,但可以避免計算過程中出現 nan 導致的潛在影響。
創建主循環,主循環中每條指令執行,從對應的寄存器讀取數據,并執行 fmla 指令,將計算結果寫到相同的寄存器中,同一條指令內部沒有數據相關。
這里有一個問題需要解釋,為什么選擇 20 個寄存器:
如果寄存器選擇太少,上一次循環可能還沒有計算完成,下一次循環讀取相同的寄存器,可能造成數據相關,因此循環里面執行的指令條數需要大于指令延遲和處理器單個周期內能夠執行的指令數的乘積,但是我們不知道這條指令延遲,但是可以估計,除了特殊的指令,延遲一般不超過 10 個時鐘周期。
Arm64 有 32 個 neon 寄存器,為什么不選擇 32 個寄存器,因為 20 個寄存器已經可以避免數據和控制相關了,測試發現使用更多的寄存器影響很小。
為了測量處理器上一條指令的執行延遲,我們需要寫出重復執行這條指令,并讓這些指令之間存在嚴格的數據冒險,盡量排除其他冒險。
制造數據冒險----讓前后兩條指令之間的數據存在真正的數據依賴(RAW),即上一條指令的輸出為下一條指令的輸入
盡可能的消除控制冒險----同上
下面是 MegPeak 測試 Arm64 上 fmla 指令延遲的核心 Code。
static int fmla_latency() {
asm volatile(
"eor v0.16b, v0.16b, v0.16b\n"
"mov x0, #0\n"
"1:\n"
"fmla v0.4s, v0.4s, v0.4s\n"
//重復 20 次
...
"fmla v0.4s, v0.4s, v0.4s\n"
"add x0, x0, #1 \n"
"cmp x0, %x[RUNS] \n"
"blt 1b \n"
:
: [RUNS] "r"(megpeak::RUNS)
: "cc", "v0", "x0"
);
return megpeak::RUNS * 20;
}
fmla v0.4s, v0.4s, v0.4s\n
這條指令重復了 20 次,這樣每條指令都依賴上一條指令的計算結果,所以存在嚴格的數據相關。
執行代碼,統計執行時間,通過執行的指令條數,可以計算出這條指令最終的延遲。
用 MegPeak 測到的數據,
可以用來干什么
MegPeak 可以測試出處理器的內存帶寬,指令的理論計算峰值,指令的延遲等信息,因此可以幫助我們:
繪制 Roofline Model 指導我們優化模型性能
評估程序的優化空間
探索指令組合的理論計算峰值
在優化具體算法的時候,可以通過 MegPeak 測試出 kernel 里面的主要指令的最大峰值,如在 Arm 上優化 fp32 Matmul 的時候,主要用到的指令是 fmla 指令,這時候可以測試程序實際運行的峰值,如果指令的峰值和程序的峰值差距越小,說明代碼優化得越好。
很多 Kernel 的優化不是單純的某一條指令就可以衡量,可能需要多條指令的組合才能代表整個 Kernel 的計算,因此我們需要探索如何組織這些指令使其達到處理器最優的性能。下面列舉在 A53 小核優化 fp32 Matmul 的過程中,由于 Matmul 是計算密集型算子,考慮通過多發射隱藏訪存指令的開銷,使用 MegPeak 配合進行分析,探索如何組合指令實現盡可能多地多發射。
因為小核上面資源有限,指令多發射有很多限制,
首先使用 MegPeak 出測試 A53 上 fp32 的 fmla 指令的計算峰值,將其定義為 100% 峰值計算性能
測試哪些指令組合可以支持雙發射
在 MegPeak 中添加 vector load 和 fmla 1:1 組合的代碼,然后測試其峰值僅僅為 float 峰值的 36%,表明 Vector load 和 fmla 不能雙發射
同樣可以測得通用寄存器 load 指令 ldr+fmla 的組合可以達到 float 峰值的 93%,說明 ldr 可以和 fmla 雙發射
同上可以測得 ins + fmla 能雙發射,ins + vector load 64 位 可以雙發射
根據 Matmul 最內層 Kernel 的 計算原理,如最內層 Kernel 的分塊大小是 8x12,那最內層需要讀取:20 個 float 數據,計算 24 次 fmla 計算
結合上面的 MegPeak 測試的信息,我們需要找到用最少時鐘完成這:20 個 float 數據 load,和 24 次 fmla 數據計算的指令組合,因此需要將盡可能多的數據 load 和 fmla 進行雙發射,隱藏數據 load 的耗時
最后的指令組合是:
使用 vector load 64 指令 + ldr + ins 組合成為一個 neon 寄存器數據,因為 ldr 和 ins 都可以和 fmla 雙發射,把他們和 fmla 放在一起可以隱藏他們的耗時
在這 3 條指令中穿插 fmla 指令,并盡可能解決數據依賴
總結
MegPeak 作為一個進行高性能計算的輔助工具,能夠使得開發人員輕松獲得目標處理器的內在的詳細信息,輔助進行對代碼的性能評估,以及優化方法設計。但是 MegPeak 也有一些需要豐富的方向:
支持獲取更多的處理器性能數據,如:L1,L2 cache 的大小,自動探索各種指令組合的雙發射情況,并大概繪制出一個處理器后端的縮略圖。如:en.wikichip.org/w/image
支持測量移動端 OpenCL 的更多細節信息,如:warp size,local memory 大小等。
關鍵詞: MegPeak