【genius_platform软件平台开发】第二十八讲:NEON指令集优化(附实例)
- 當在ARM芯片上進行一些例如圖像處理等計算的時候,常常會因為計算量太大造成計算幀率較低的情況。因而,需要選擇一種更加簡單快捷的計算方式以獲得處理速度上的提升。ARM NEON就是一個不錯的選擇.
※ Neon指令優化
-
NEON是一種SIMD(Single Instruction Multiple Data)*指令,也就是說,NEON可以把若干源(source)操作數(operand)打包放到一個源寄存器中,對他們執行相同的操作,產生若干目的(dest)操作數,這種方式也叫向量化(vectorization)。
-
可能你對這個描述還不夠清晰,簡單來說,就是:NEON指令優化的精髓就在于同時在不同通道內進行并行運算。通常可用于圖像等矩陣數據的循環優化。
-
更簡單的說,就是,將Neon寄存器分為多個通道,每個通道存儲一個數據。一條對Neon寄存器的計算指令,實際上,是對各通道的數據分別的計算指令。即寄存器位寬,直接影響到數據的通道數。
-
例如:在ARMv7的NEON unit中,register file總大小是1024-bit,可以劃分為16個128-bit的Q-register(Quadword register)或者32個64-bit的D-register(Dualword register),也就是說,最長的寄存器位寬是128-bit。那么,假設我們采用32-bit單精度浮點數float來做浮點運算,那么可以把最多128/32=4個浮點數打包放到Q-register中做運算,即4個4個參與計算,從而提高吞吐量,減少loop次數。
-
Neon指令的使用
主流支持目標平臺為ARM CPU的編譯器基本都支持NEON指令。可以通過在代碼中嵌入NEON匯編來使用NEON,但是更加常見的方式是通過類似C函數的NEON Instrinsic來編寫NEON代碼。本文統一采用后者。
※ 硬件平臺
- 本文的例子都是基于ARMV7架構平臺。ARMV7架構包含:
16個通用寄存器(32bit),R0-R15
16個NEON寄存器(128bit),Q0-Q15(同時也可以被視為32個64bit的寄存器,D0-D31)
16個VFP寄存器(32bit),S0-S15
其中:NEON和VFP的區別在于VFP是加速浮點計算的硬件不具備數據并行能力,同時VFP更盡興雙精度浮點數(double)的計算,NEON只有單精度浮點計算能力。
● 頭文件和編譯選項
- 在使用NEON Instrinsic來進行編寫NEON代碼前,需要引入頭文件:
- 同時,在編譯的時候,需要指定編譯參數。如果使用CMakeLists.txt,可以指定:
- 關于編譯選項,可以參考:ARM平臺NEON指令的編譯和優化
※ NEON Instrinsic詳細解釋
● 數據類型
-
對于數據類型的命名,一般遵循這樣的規則:
<基本類型>x<lane個數>x<向量個數>_t
其中,向量個數如果省略表示只有一個。
基本類型:int8,int16,int32,int64,uint8,uint16,uint32,uint64,float16,float32 -
lane個數表示并行處理的基本類型數據的個數。
按照上述的規則,比如:
float32x4_t
● 指令函數
-
對于指令函數的命名,一般遵循這樣的規則:
v<指令名>[后綴]_<數據基本類型簡寫>
-
其中,后綴如果沒有,表示64位并行;如果后綴是q,表示128位并行;如果后綴是l,表示長指令,輸出數據的基本類型位數是輸入的2倍;如果后綴是n,表示窄指令,輸出數據的基本類型位數是輸入的一半。
數據基本類型簡寫:s8,s16,s32,s64,u8,u16,u32,u64,f16,f32。按照上述的規則,比如:
● 指令名
-
Neon的指令名主要分為:算術和位運算指令、數據移動指令、訪存指令。
算術和位運算指令:包括add(加法),sub(減法),mul(乘法)這些基本指令。 -
實際編程中經常要在不同NEON數據類型間轉移數據,有時還要按lane來get/set向量值,NEON intrinsics也提供了這類操作。
dup[后綴]n<數據基本類型簡寫>:用同一個標量值初始化一個向量全部的lane;
set[后綴]lane<數據基本類型簡寫>:對指定的一個lane進行設置
get[后綴]lane<數據基本類型簡寫>:獲取指定的一個lane的值
mov[后綴]_<數據基本類型簡寫>:數據間移動
-
NEON訪存指令可以將內存讀到NEON數據類型中去,或者將NEON數據類型寫進內存。可以支持一次讀寫多向量數據類型。
ld<向量數>[后綴]<數據基本類型簡寫>:讀內存
st<向量數>[后綴]<數據基本類型簡寫>:寫內存
實例
- 實例內容:對于1280 * 720 * 3的圖片數據,需要對每個像素點進行同樣的加法和乘法運算,比較非Neon和Neon兩種方式的耗時。源碼:
- 編寫CMakeLists.txt,用于項目編譯:
- 在同級目錄下編寫main.sh,進行項目編譯:
- 將生成的可執行文件main,push到設備端進行運行,最終的運行結果:
- 可以看出,使用Neon指令集優化,省下了近60.71%的運行時間。
總結
以上是生活随笔為你收集整理的【genius_platform软件平台开发】第二十八讲:NEON指令集优化(附实例)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021-06-09
- 下一篇: ARM SIMD NEON 简介 (翻译