一、SIMD
Arm NEON 是適用于 Arm Cortex-A 和 Cortex-R 系列處理器的一種 SIMD(Single Instruction Multiple Data)擴(kuò)展架構(gòu)。
SIMD 采用一個(gè)控制器來控制多個(gè)處理器,同時(shí)對(duì)一組數(shù)據(jù)(又稱“數(shù)據(jù)向量”)中的每個(gè)數(shù)據(jù)分別執(zhí)行相同操作,從而實(shí)現(xiàn)并行技術(shù)。
SIMD 特別適用于一些常見的任務(wù),如音頻圖像處理。大部分現(xiàn)代 CPU 設(shè)計(jì)都包含了 SIMD 指令,來提高多媒體使用的性能。
SIMD 操作示意圖
如上圖所示,標(biāo)量運(yùn)算時(shí)一次只能對(duì)一對(duì)數(shù)據(jù)執(zhí)行乘法操作,而采用 SIMD 乘法指令,則一次可以對(duì)四對(duì)數(shù)據(jù)同時(shí)執(zhí)行乘法操作。
A. 指令流與數(shù)據(jù)流
費(fèi)林分類法根據(jù)指令流(Instruction)和數(shù)據(jù)流(Data)的處理方式進(jìn)行分類,可分成四種計(jì)算機(jī)類型:
費(fèi)林分類示意圖
1. SISD(Single Instruction Single Data)
機(jī)器的硬件不支持任何形式的并行計(jì)算,所有的指令都是串行執(zhí)行。單個(gè)核心執(zhí)行單個(gè)指令流 , 操作存儲(chǔ)在單個(gè)內(nèi)存中的數(shù)據(jù) , 每次一個(gè)操作。早期的計(jì)算機(jī)都是SISD機(jī)器,如馮諾.依曼架構(gòu),IBM PC機(jī)等。
2. MISD(Multiple Instruction Single Data)
是采用多個(gè)指令流來處理單個(gè)數(shù)據(jù)流。由于實(shí)際情況中,采用多指令流處理多數(shù)據(jù)流才是更有效的方法,因此MISD只是作為理論模型出現(xiàn),沒有投入到實(shí)際應(yīng)用之中。
3. MIMD(Mutiple Instruction Mutiple Data)
計(jì)算機(jī)具有多個(gè)異步和獨(dú)立工作的處理器。在任何時(shí)鐘周期內(nèi),不同的處理器可以在不同的數(shù)據(jù)片段上執(zhí)行不同的指令,也即是同時(shí)執(zhí)行多個(gè)指令流,而這些指令流分別對(duì)不同數(shù)據(jù)流進(jìn)行操作。MIMD架構(gòu)可以用于諸如計(jì)算機(jī)輔助設(shè)計(jì)、計(jì)算機(jī)輔助制造、仿真、建模、通信交換機(jī)的多個(gè)應(yīng)用領(lǐng)域。
除了以上模型外,由NVIDIA公司生產(chǎn)的GPU引入SIMT體系結(jié)構(gòu):
4. SIMT(Single Instruction Multiple Threads)
類似 CPU 上的多線程,所有的核心各有各的執(zhí)行單元,數(shù)據(jù)不同,執(zhí)行的命令是相同的。多個(gè)線程各有各的處理單元,和 SIMD 共用一個(gè) ALU 不同。
SIMT 示意圖
B. SIMD 特點(diǎn)及發(fā)展趨勢(shì)
1. SIMD 優(yōu)勢(shì)與不足
2. SIMD發(fā)展趨勢(shì)
以Arm架構(gòu)下的下一代 SIMD 指令集?SVE(Scalable Vector Extension,可擴(kuò)展矢量指令)為例,其是_針對(duì)高性能計(jì)算(HPC)和機(jī)器學(xué)習(xí)等領(lǐng)域開發(fā)的一套全新的矢量指令集_。
SVE 指令集中有很多概念與 NEON 指令集類似,例如矢量、通道、數(shù)據(jù)元素等。
SVE指令集也提出了一個(gè)全新的概念:可變矢量長(zhǎng)度編程模型。
SVE 可擴(kuò)展模型
傳統(tǒng)的 SIMD 指令集采用固定大小的向量寄存器,例如 NEON 指令集采用固定的 64/128 位長(zhǎng)度的矢量寄存器。
而支持 VLA 編程模型的 SVE 指令集則支持可變長(zhǎng)度的矢量寄存器。因此允許芯片設(shè)計(jì)者根據(jù)負(fù)載和成本來選擇一個(gè)合適的矢量長(zhǎng)度。
SVE 指令集的矢量寄存器的長(zhǎng)度最小支持 128 位,最大可以支持 2048 位,以 128 位為增量。SVE 設(shè)計(jì)確保同一個(gè)應(yīng)用程序可以在支持不同矢量長(zhǎng)度的 SVE 指令機(jī)器上運(yùn)行,而不需要重新編譯代碼。
Arm 在 2019 年便推出了 SVE2,以最新的 Armv9 為基礎(chǔ),擴(kuò)充了更多的運(yùn)算類型以全面替代 NEON,同時(shí)增加了矩陣相關(guān)運(yùn)算的支持。
二、 Arm?的 SIMD 指令集
1. Arm?處理器的 SIMD 支持 - NEON
Arm NEON 單元默認(rèn)包含在 Cortex-A7 和 Cortex-A15 處理器中,但在其他 Armv7 Cortex-A 系列處理器中是可選的,某些實(shí)現(xiàn) Armv7–A 或 Armv7–R 架構(gòu)配置文件的Cortex-A 系列處理器可能不包含NEON單元。
符合 Armv7 的內(nèi)核的可能組合有以下四種:
因此必須首先確認(rèn)處理器是否支持 NEON 和 VFP。可以在編譯和運(yùn)行的時(shí)候進(jìn)行檢查。
NEON 發(fā)展史
2. ARM 處理器的 SIMD 支持檢查
2.1 編譯階段檢查
檢測(cè) NEON 單元是否存在的最簡(jiǎn)單方法。在 Arm 編譯器工具鏈(armcc)v4.0 及更高版本或 GCC 中,檢查預(yù)定義宏?ARM_NEON?或者?__arm_neon?是否開啟。
armasm?等效的預(yù)定義宏是?TARGET_FEATURE_NEON。
2.2 運(yùn)行階段檢查
在運(yùn)行時(shí)檢測(cè) NEON 單元需要操作系統(tǒng)的幫助。ARM 架構(gòu)有意不向用戶模式應(yīng)用程序公開處理器功能。在Linux下,/proc/cpuinfo?以可讀的形式包含此信息,比如:
在Tegra(帶有FPU的雙核Cortex-A9處理器)
$ /proc/cpuinfo swp half thumb fastmult vfp edsp thumbee vfpv3 vfpv3d16
帶有 NEON 單元的 ARM Cortex-A9 處理器
$ /proc/cpuinfo swp half thumb fastmult vfp edsp thumbee neon vfpv3
由于?/proc/cpuinfo?輸出是基于文本的,因此通常首選查看輔助向量?/proc/self/auxv,其包含二進(jìn)制格式的內(nèi)核?hwcap,可以輕松地在?/proc/self/auxv?文件中搜索?AT_HWCAP?記錄,以檢查?HWCAP_NEON?位(4096)。
某些 Linux 發(fā)行版?ld.so?鏈接器腳本被修改為通過 glibc 讀取?hwcap?,并為啟用 NEON 的共享庫添加額外的搜索路徑。
3. 指令集關(guān)系
在Armv7中,NEON 與 VFP 指令集具有以下關(guān)系:
具有 NEON 單元但沒有VFP單元的處理器無法在硬件中執(zhí)行浮點(diǎn)運(yùn)算。
由于 NEON SIMD 操作更有效地執(zhí)行向量計(jì)算,因此從 ARMv7 的引入開始,VFP 單元中的向量模式操作已被棄用。因此,VFP 單元有時(shí)也稱為浮點(diǎn)單元(FPU)。
VFP 可以提供完全兼容 IEEE-754 的浮點(diǎn)運(yùn)算,Armv7 NEON 單元中的單精度運(yùn)算不完全符合 IEEE-754。
NEON不能取代 VFP。VFP 提供了一些在 NEON 指令集中沒有等效實(shí)現(xiàn)的專用指令。
半精度指令僅適用于包含半精度擴(kuò)展的 NEON 和 VFP 系統(tǒng)。
在Armv8中,VFP已被NEON取代,以上問題如 NEON 并不完全符合 IEEE 754 標(biāo)準(zhǔn),并且有一些指令 VFP 支持而 NEON 不支持的問題已在 ARMv8 中得到解決。
三、NEON
NEON 是適用于 Arm Cortex-A 系列處理器的一種128位 SIMD 擴(kuò)展結(jié)構(gòu),每個(gè)處理器核心均有一個(gè) NEON 單元,因此可以實(shí)現(xiàn)多線程并行的加速效果。
1. NEON基本原理
1.1 NEON 指令執(zhí)行流程
上圖為 NEON 單元完成加速計(jì)算的流程圖。其中向量寄存器中的每個(gè)元素同步執(zhí)行計(jì)算,以此來加速計(jì)算過程。
1.2 NEON 計(jì)算資源
NEON 與 Arm?處理器資源關(guān)系
- NEON 單元作為 Arm指令集的擴(kuò)展,使用獨(dú)立于 ARM 原有寄存器的 64位 或 128 位寄存器進(jìn)行 SIMD 處理,在 64位 寄存器的寄存器文件上運(yùn)行。
- NEON 和 VFP 單元完全集成到了處理器中,并共享處理器資源以進(jìn)行整數(shù)運(yùn)算、循環(huán)控制和緩存。
與硬件加速器相比,這顯著降低了面積和功耗成本。并且其還使用更簡(jiǎn)單的編程模型,因?yàn)镹EON 單元使用與應(yīng)用程序相同的地址空間。
NEON 與 VFP 資源關(guān)系
NEON 寄存器與 VFP 寄存器重疊,Armv7 有 32 個(gè) NEON D 寄存器,如下圖所示。
NEON 寄存器
2. NEON指令
2.1 自動(dòng)矢量化
向量化編譯器可以使用 C 或 C++ 源代碼,以一種能夠有效使用 NEO N硬件的方式對(duì)其進(jìn)行矢量化。這意味著可以通過編寫可移植的 C 代碼,同時(shí)仍然可以獲得 NEON 指令所帶來的性能水平。
為了幫助矢量化,將循環(huán)迭代次數(shù)設(shè)為矢量長(zhǎng)度的倍數(shù)。GCC 和 ARM 編譯器工具鏈都具有為 NEON 技術(shù)啟用自動(dòng)矢量化的選項(xiàng)。
2.2 NEON匯編
對(duì)于性能要求特別高的程序,手工編寫匯編代碼是更適合的方式。
GNU 匯編器(gas) 和 Arm Compile r工具鏈匯編器(armasm)都支持 NEON 指令的匯編。
編寫匯編函數(shù)時(shí),需要了解?Arm?EABI,其定義了如何使用寄存器。ARM嵌入式應(yīng)用程序二進(jìn)制接口(EABI)指定哪些寄存器用于傳遞參數(shù)、返回結(jié)果或必須保留,指定了除Arm內(nèi)核寄存器之外的32個(gè)D寄存器的使用。下圖對(duì)寄存器功能進(jìn)行了總結(jié)。
寄存器功能
2.3 NEON Intrinsics
NEON intrinsic 函數(shù)提供了一種編寫 NEON 代碼的方法,該方法比匯編代碼更易于維護(hù),同時(shí)仍然可以控制生成的 NEON 指令。
內(nèi)部函數(shù)使用與 D 和 Q NEON 寄存器對(duì)應(yīng)的新數(shù)據(jù)類型。數(shù)據(jù)類型支持創(chuàng)建直接映射到NEON 寄存器的 C 變量。
NEON intrinsic 函數(shù)的編寫類似于使用這些變量作為參數(shù)或返回值的函數(shù)調(diào)用。編譯器做了一些通常與編寫匯編語言相關(guān)的繁重工作,例如:
寄存器分配
代碼調(diào)度或重新排序指令
intrinsic 缺點(diǎn)
無法讓編譯器準(zhǔn)確輸出想要的代碼,因此在轉(zhuǎn)向NEON匯編代碼時(shí)仍有一些改進(jìn)的可能性。
NEON 指令簡(jiǎn)類型
NEON 數(shù)據(jù)處理指令可以分為正常指令、長(zhǎng)指令、寬指令、窄指令和飽和指令。
以 Intrinsic 的長(zhǎng)指令為例?int16x8_t vaddl_s8(int8x8_t __a, int8x8_t __b);
- 上面的函數(shù)將兩個(gè)64位的 D 寄存器向量(每個(gè)向量包含8個(gè)8位數(shù)字)相加,生成一個(gè)包含8個(gè)16位數(shù)字的向量(存儲(chǔ)在128位的Q寄存器中),從而避免相加的結(jié)果溢出。
四、其他 SIMD 技術(shù)
1. 其他平臺(tái)上的 SIMD 技術(shù)
SIMD 處理不是 Arm 獨(dú)有的,下圖將其與 x86 和 Altivec 進(jìn)行了比較。
SIMD 對(duì)比
2. 與專用 DSP 對(duì)比
許多基于 Arm 的 SOC 中還包含 DSP 等協(xié)處理硬件,因此可以同時(shí)包含 NEON 單元和DSP。相對(duì)于 DSP,NEON 的特點(diǎn)有:
五、總結(jié)
本節(jié)主要介紹基本 SIMD 及其他的指令流與數(shù)據(jù)流的處理方式,NEON 的基本原理、指令以及與其他平臺(tái)及硬件的對(duì)比。
編輯:黃飛
?
評(píng)論
查看更多