1.簡(jiǎn)介
讀過(guò)上一篇文章“ARM NEON快速上手指南”之后,相信你已經(jīng)對(duì)ARM NEON編程有了基本的認(rèn)識(shí)。但在真正利用ARM NEON優(yōu)化程序性能時(shí),還有很多編程技巧和注意事項(xiàng)。本文將結(jié)合本人的一些開發(fā)經(jīng)歷,介紹NEON編程中的一些常見優(yōu)化技巧,希望能對(duì)用戶在NEON實(shí)際開發(fā)中有些借鑒意義。
2.NEON優(yōu)化技術(shù)
在利用NEON優(yōu)化程序時(shí),有下述幾項(xiàng)比較通用的優(yōu)化技巧。
2.1 降低數(shù)據(jù)依賴性
在ARM v7-A NEON指令通常需要3~9個(gè)指令周期,NEON指令比ARM指令需要更多周期數(shù)。因此,為了減少指令延時(shí),最好避免將當(dāng)前指令的目的寄存器當(dāng)作下條指令的源寄存器。如下例所示:
// C代碼
float SumSquareError_C(const float* src_a, const float* src_b, int count)
{
float sse = 0u;
int i;
for (i = 0; i < count; ++i) {
float diff = src_a[i] - src_b[i];
sse += (float)(diff * diff);
}
return sse;
}
// NEON實(shí)現(xiàn)一
float SumSquareError_NEON1(const float* src_a, const float* src_b, int count)
{
float sse;
asm volatile (
"veor q8, q8, q8
"
"veor q9, q9, q9
"
"veor q10, q10, q10
"
"veor q11, q11, q11
"
"1:
"
"vld1.32 {q0, q1}, [%0]!
"
"vld1.32 {q2, q3}, [%0]!
"
"vld1.32 {q12, q13}, [%1]!
"
"vld1.32 {q14, q15}, [%1]!
"
"subs %2, %2, #16
"
// q0, q1, q2, q3 是vsub的目的地寄存器.
// 也是vmla的源寄存器。
"vsub.f32 q0, q0, q12
"
"vmla.f32 q8, q0, q0
"
"vsub.f32 q1, q1, q13
"
"vmla.f32 q9, q1, q1
"
"vsub.f32 q2, q2, q14
"
"vmla.f32 q10, q2, q2
"
"vsub.f32 q3, q3, q15
"
"vmla.f32 q11, q3, q3
"
"bgt 1b
"
"vadd.f32 q8, q8, q9
"
"vadd.f32 q10, q10, q11
"
"vadd.f32 q11, q8, q10
"
"vpadd.f32 d2, d22, d23
"
"vpadd.f32 d0, d2, d2
"
"vmov.32 %3, d0[0]
"
: "+r"(src_a),
"+r"(src_b),
"+r"(count),
"=r"(sse)
:
: "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11","q12", "q13","q14", "q15");
return sse;
}
// NEON實(shí)現(xiàn)二
float SumSquareError_NEON2(const float* src_a, const float* src_b, int count)
{
float sse;
asm volatile (
"veor q8, q8, q8
"
"veor q9, q9, q9
"
"veor q10, q10, q10
"
"veor q11, q11, q11
"
"1:
"
"vld1.32 {q0, q1}, [%0]!
"
"vld1.32 {q2, q3}, [%0]!
"
"vld1.32 {q12, q13}, [%1]!
"
"vld1.32 {q14, q15}, [%1]!
"
"subs %2, %2, #16
"
"vsub.f32 q0, q0, q12
"
"vsub.f32 q1, q1, q13
"
"vsub.f32 q2, q2, q14
"
"vsub.f32 q3, q3, q15
"
"vmla.f32 q8, q0, q0
"
"vmla.f32 q9, q1, q1
"
"vmla.f32 q10, q2, q2
"
"vmla.f32 q11, q3, q3
"
"bgt 1b
"
"vadd.f32 q8, q8, q9
"
"vadd.f32 q10, q10, q11
"
"vadd.f32 q11, q8, q10
"
"vpadd.f32 d2, d22, d23
"
"vpadd.f32 d0, d2, d2
"
"vmov.32 %3, d0[0]
"
: "+r"(src_a),
"+r"(src_b),
"+r"(count),
"=r"(sse)
:
: "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "q13","q14", "q15");
return sse;
}
在NEON實(shí)現(xiàn)一中,我們把目的寄存器立刻當(dāng)作源寄存器;在NEON實(shí)現(xiàn)二中,我們重新排布了指令,并給予目的寄存器盡量多的延時(shí)。經(jīng)過(guò)測(cè)試實(shí)現(xiàn)二比實(shí)現(xiàn)一快30%。由此可見,降低數(shù)據(jù)依賴性對(duì)于提高程序性能有重要意義。一個(gè)好消息是編譯器能自動(dòng)調(diào)整NEON intrinsics以降低數(shù)據(jù)依賴性。這個(gè)利用NEON intrinsics的一個(gè)很大優(yōu)勢(shì)。
2.2 減少跳轉(zhuǎn)
NEON指令集沒(méi)有跳轉(zhuǎn)指令,當(dāng)需要跳轉(zhuǎn)時(shí),我們需要借助ARM指令。在ARM處理器中,分支預(yù)測(cè)技術(shù)被廣泛使用。但是一旦分支預(yù)測(cè)失敗,懲罰還是比較高的。因此我們最好盡量減少跳轉(zhuǎn)指令的使用。其實(shí),在有些情況下,我們可以用邏輯運(yùn)算來(lái)代替跳轉(zhuǎn),如下例所示:
// C實(shí)現(xiàn)
if( flag )
{
dst[x * 4] = a;
dst[x * 4 + 1] = a;
dst[x * 4 + 2] = a;
dst[x * 4 + 3] = a;
}
else
{
dst[x * 4] = b;
dst[x * 4 + 1] = b;
dst[x * 4 + 2] = b;
dst[x * 4 + 3] = b;
}
// NEON實(shí)現(xiàn)
//dst[x * 4] = (a&Eflag) | (b&~Eflag);
//dst[x * 4 + 1] = (a&Eflag) | (b&~Eflag);
//dst[x * 4 + 2] = (a&Eflag) | (b&~Eflag);
//dst[x * 4 + 3] = (a&Eflag) | (b&~Eflag);
VBSL qFlag, qA, qB
ARM NEON指令集提供了下列指令來(lái)幫助用戶實(shí)現(xiàn)上述邏輯實(shí)現(xiàn):
? VCEQ, VCGE, VCGT, VCLE, VCLT……
? VBIT, VBIF, VBSL……
減少跳轉(zhuǎn),不僅僅是在NEON中使用的技巧,是一個(gè)比較通用的問(wèn)題。即使在C程序中,這個(gè)問(wèn)題也是值得注意的。
2.3 其它技巧
在ARM NEON編程時(shí),一種功能有時(shí)有多種實(shí)現(xiàn)方式,但是更少的指令不總是意味著更好的性能,要依據(jù)測(cè)試結(jié)果和profiling數(shù)據(jù),具體問(wèn)題具體分析。下面列出來(lái)我遇到的一些特殊情況。2.3.1 浮點(diǎn)累加指令通常情況下,我們會(huì)用VMLA/VMLS來(lái)代替VMUL + VADD/ VMUL + VSUB,這樣使用較少的指令,完成更多的功能。但是與浮點(diǎn)VMUL相比,浮點(diǎn)VMLA/VMLS具有更長(zhǎng)的指令延時(shí),如果在指令延時(shí)中間不能插入其它計(jì)算的情況下,使用浮點(diǎn)VMUL + VADD/ VMUL + VSUB反而具有更好的性能。一個(gè)真實(shí)例子就是Ne10庫(kù)函數(shù)的浮點(diǎn)FIR函數(shù)。代碼片段如下所示:
實(shí)現(xiàn)1:在兩條VMLA指令之間,僅有VEXT指令。而根據(jù)指令延時(shí)表,VMLA需要9個(gè)周期。
實(shí)現(xiàn)2:對(duì)于qAcc0,依然存在指令延時(shí)。但是VADD/VMUL只需要5個(gè)周期。下列代碼中周期n粗略地表示了指令執(zhí)行需要的周期數(shù)。與實(shí)現(xiàn)1相比,實(shí)現(xiàn)2節(jié)省了6個(gè)周期。性能測(cè)試也表明實(shí)現(xiàn)2具有更好的性能。
實(shí)現(xiàn) 1: VMLA
VEXT qTemp1,qInp,qTemp,#1
VMLA qAcc0,qInp,dCoeff_0[0]-- cycle 0
VEXT qTemp2,qInp,qTemp,#2
VMLA qAcc0,qTemp1,dCoeff_0[1] -- cycle 9
VEXT qTemp3,qInp,qTemp,#3
VMLA qAcc0,qTemp2,dCoeff_1[0] -- cycle 18
VMLA qAcc0,qTemp3,dCoeff_1[1] -- cycle 27
得到最終結(jié)果 qAcc0需要36個(gè)指令周期。
實(shí)現(xiàn) 2: VMUL+VADD
VEXT qTemp1,qInp,qTemp,#1
VMLA qAcc0,qInp,dCoeff_0[0] ]-- cycle 0
VMUL qAcc1,qTemp1,dCoeff_0[1]
VEXT qTemp2,qInp,qTemp,#2
VMUL qAcc2,qTemp2,dCoeff_1[0]
VADD qAcc0, qAcc0, qAcc1-- cycle 9
VEXT qTemp3,qInp,qTemp,#3
VMUL qAcc3,qTemp3,dCoeff_1[1]
VADD qAcc0, qAcc0, qAcc2-- cycle 14
VADD qAcc0, qAcc0, qAcc3-- cycle 19
得到最終結(jié)果 qAcc0需要24個(gè)指令周期。
與實(shí)現(xiàn)1相比,三條VADD指令需要6個(gè)發(fā)射指令周期。總共需要 30個(gè)指令周期。
modules/dsp/NE10_fir.neon.s:line 195
指令延時(shí)請(qǐng)參考下表:
| Name | Format | Cycles | Result |
|---|---|---|---|
| VADD/VSUB/VMUL | Qd,Qn,Dm | 2 | 5 |
| VMLA/VMLS | Qd,Qn,Dm | 2 | 9 |
表格來(lái)源于Cortex-A9 NEON Media Processing Engine Revision: r4p1 Technical Reference Manual: 3.4.8。
表格中:? Cycles:指令發(fā)射時(shí)間
? Result:指令執(zhí)行時(shí)間
2.4 小結(jié)
總結(jié)起來(lái),NEON的優(yōu)化技巧主要有以下幾點(diǎn)
? 盡量利用指令執(zhí)行延時(shí),合理安排指令順序
? 少用跳轉(zhuǎn)
? 注意cache命中率
審核編輯:郭婷
-
ARM
+關(guān)注
關(guān)注
135文章
9554瀏覽量
392091 -
寄存器
+關(guān)注
關(guān)注
31文章
5609瀏覽量
130016
原文標(biāo)題:Arm NEON學(xué)習(xí)(二)優(yōu)化技術(shù)
文章出處:【微信號(hào):Ithingedu,微信公眾號(hào):安芯教育科技】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
爬壁機(jī)器人磁鐵的一些常見問(wèn)題
CW32系統(tǒng)有哪些常見問(wèn)題?
關(guān)于六類網(wǎng)線一些問(wèn)題的解答
貼片電容精度J±5%的一些詳細(xì)知識(shí)
對(duì)浮點(diǎn)指令擴(kuò)展中一些問(wèn)題的解決與分享
蜂鳥E203的浮點(diǎn)指令集F的一些實(shí)現(xiàn)細(xì)節(jié)
Vivado浮點(diǎn)數(shù)IP核的一些設(shè)置注意點(diǎn)
在Ubuntu20.04系統(tǒng)中訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型的一些經(jīng)驗(yàn)
射頻工程師需要知道的一些常見轉(zhuǎn)接頭
如何優(yōu)化可編程電源控制環(huán)路參數(shù)?
在低功耗藍(lán)牙產(chǎn)品開發(fā)的過(guò)程中,會(huì)涉及到一些參數(shù)的選擇和設(shè)定,這些參數(shù)是什么意思,該如何設(shè)定呢?(藍(lán)牙廣播)
HarmonyOS優(yōu)化應(yīng)用內(nèi)存占用問(wèn)題性能優(yōu)化一
Debian和Ubuntu哪個(gè)好一些?
PCBA加工返修全攻略:常見問(wèn)題一網(wǎng)打盡
樹莓派在自動(dòng)化控制項(xiàng)目中的一些潛在應(yīng)用
NEON編程中的一些常見優(yōu)化技巧
評(píng)論