91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

NEON編程中的一些常見優(yōu)化技巧

安芯教育科技 ? 來(lái)源:安謀科技學(xué)堂 ? 作者:安謀科技學(xué)堂 ? 2022-12-12 09:11 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

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命中率

審核編輯:郭婷


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • ARM
    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)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    爬壁機(jī)器人磁鐵的一些常見問(wèn)題

    爬壁機(jī)器人近幾年比較火,它是類能夠在垂直墻面、天花板、傾斜表面上移動(dòng)和作業(yè)的特種機(jī)器人,今天我們不聊其它,只聊下關(guān)于磁吸附應(yīng)用的磁鐵,以下是小編整理的關(guān)于爬壁機(jī)器人中磁鐵的一些常見
    的頭像 發(fā)表于 01-09 10:06 ?278次閱讀
    爬壁機(jī)器人磁鐵的<b class='flag-5'>一些</b><b class='flag-5'>常見</b>問(wèn)題

    CW32系統(tǒng)有哪些常見問(wèn)題?

    在CW32系統(tǒng),可能會(huì)遇到一些常見問(wèn)題,包括但不限于: 重復(fù)定義函數(shù):例如在a.c里定義了函數(shù)void func(),在b.c里也定義了個(gè)void func()。這會(huì)導(dǎo)致編譯時(shí)出
    發(fā)表于 12-15 06:47

    關(guān)于六類網(wǎng)線一些問(wèn)題的解答

    今天我們就圍繞網(wǎng)友一些常見的關(guān)于六類網(wǎng)線的問(wèn)題進(jìn)行下匯總式解答: 問(wèn) 六類網(wǎng)線可以當(dāng)電源用嗎? 答 六類網(wǎng)線并不是設(shè)計(jì)用于傳輸電力的電纜,因此般不建議將其用于電源傳輸。 盡管六類網(wǎng)
    的頭像 發(fā)表于 12-09 11:13 ?570次閱讀

    貼片電容精度J±5%的一些詳細(xì)知識(shí)

    貼片電容精度J±5%表示電容的實(shí)際值與標(biāo)稱值之間的偏差范圍在±5%以內(nèi) ,以下是關(guān)于貼片電容精度J±5%的一些詳細(xì)知識(shí): 、精度等級(jí)含義 J±5% :字母“J”在貼片電容的標(biāo)識(shí)通常表示標(biāo)稱精度
    的頭像 發(fā)表于 11-20 14:38 ?663次閱讀
    貼片電容精度J±5%的<b class='flag-5'>一些</b>詳細(xì)知識(shí)

    對(duì)浮點(diǎn)指令擴(kuò)展中一些問(wèn)題的解決與分享

    出現(xiàn)無(wú)法寫的情況。 結(jié)論 以上就是我們組在擴(kuò)展浮點(diǎn)指令中出現(xiàn)的一些問(wèn)題,這些問(wèn)題總體上歸結(jié)于對(duì)蜂鳥的代碼沒(méi)有整體性的把握,對(duì)內(nèi)容的掌握程度還不夠。在后續(xù)的工作應(yīng)注意理清功能的整體架構(gòu)而對(duì)所有的相關(guān)部分進(jìn)行修改。
    發(fā)表于 10-24 11:47

    蜂鳥E203的浮點(diǎn)指令集F的一些實(shí)現(xiàn)細(xì)節(jié)

    周期。 總結(jié) 本文介紹的內(nèi)容是為了完成基礎(chǔ)功能:對(duì)蜂鳥E203 RISC-V內(nèi)核的微架構(gòu)實(shí)現(xiàn)進(jìn)行優(yōu)化,在添加F拓展的過(guò)程一些記錄。
    發(fā)表于 10-24 08:57

    Vivado浮點(diǎn)數(shù)IP核的一些設(shè)置注意點(diǎn)

    : 總結(jié) 本文介紹的內(nèi)容是為了完成基礎(chǔ)功能:對(duì)蜂鳥E203 RISC-V內(nèi)核的微架構(gòu)實(shí)現(xiàn)進(jìn)行優(yōu)化,在添加F拓展的過(guò)程一些記錄。
    發(fā)表于 10-24 06:25

    在Ubuntu20.04系統(tǒng)訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型的一些經(jīng)驗(yàn)

    本帖欲分享在Ubuntu20.04系統(tǒng)訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型的一些經(jīng)驗(yàn)。我們采用jupyter notebook作為開發(fā)IDE,以TensorFlow2為訓(xùn)練框架,目標(biāo)是訓(xùn)練個(gè)手寫數(shù)字識(shí)別的神經(jīng)網(wǎng)絡(luò)
    發(fā)表于 10-22 07:03

    射頻工程師需要知道的一些常見轉(zhuǎn)接頭

    ,是由于轉(zhuǎn)接頭的損壞造成的,而且有些接頭的連接固定的方式不對(duì),每次修好的儀器,過(guò)去后客戶又按照他們?cè)瓉?lái)的方式去擰緊了。特別是在一些生產(chǎn)型的企業(yè),由于操作人員流動(dòng)性比較
    的頭像 發(fā)表于 08-06 17:39 ?1235次閱讀
    射頻工程師需要知道的<b class='flag-5'>一些</b><b class='flag-5'>常見</b>轉(zhuǎn)接頭

    如何優(yōu)化編程電源控制環(huán)路參數(shù)?

    時(shí)環(huán)路相位裕度僅25°,輸出電壓振蕩(頻率10kHz)。 優(yōu)化措施:在補(bǔ)償網(wǎng)絡(luò)增加個(gè)小電容(10pF),引入個(gè)高頻極點(diǎn)衰減振蕩;調(diào)整補(bǔ)償電容CCOMP?從10nF增至22nF,提
    發(fā)表于 07-02 15:56

    在低功耗藍(lán)牙產(chǎn)品開發(fā)的過(guò)程,會(huì)涉及到一些參數(shù)的選擇和設(shè)定,這些參數(shù)是什么意思,該如何設(shè)定呢?(藍(lán)牙廣播)

    在低功耗藍(lán)牙產(chǎn)品開發(fā)的過(guò)程,會(huì)涉及到一些參數(shù)的選擇和設(shè)定,這些參數(shù)是什么意思,該如何設(shè)定呢?在此介紹一些: 藍(lán)牙的廣播類型(Advertising Type) 可連接廣播(ADV_IND):允許
    發(fā)表于 06-25 18:25

    HarmonyOS優(yōu)化應(yīng)用內(nèi)存占用問(wèn)題性能優(yōu)化

    應(yīng)用開發(fā)過(guò)程中注重內(nèi)存管理,積極采取措施來(lái)減少內(nèi)存占用,以優(yōu)化應(yīng)用程序的性能和用戶體驗(yàn)。 HarmonyOS提供了一些內(nèi)存管理的工具和接口,幫助開發(fā)者有效地管理內(nèi)存資源: onMemoryLevel接口
    發(fā)表于 05-21 11:27

    Debian和Ubuntu哪個(gè)好一些?

    兼容性對(duì)比Debian和Ubuntu哪個(gè)好一些,并為您揭示如何通過(guò)RAKsmart服務(wù)器釋放Linux系統(tǒng)的最大潛能。
    的頭像 發(fā)表于 05-07 10:58 ?1162次閱讀

    PCBA加工返修全攻略:常見問(wèn)題網(wǎng)打盡

    現(xiàn)代PCBA工藝已經(jīng)非常成熟,但在生產(chǎn)和組裝過(guò)程依然難免會(huì)遇到一些質(zhì)量問(wèn)題,導(dǎo)致返修工作增加。為了解決這些問(wèn)題,并提高產(chǎn)品的最終質(zhì)量,本文將詳細(xì)探討PCBA返修中常見的問(wèn)題及其對(duì)應(yīng)的解決方案。 PCBA
    的頭像 發(fā)表于 04-02 18:00 ?1014次閱讀

    樹莓派在自動(dòng)化控制項(xiàng)目中的一些潛在應(yīng)用

    自動(dòng)化控制項(xiàng)目中的一些潛在應(yīng)用。之前,我們已經(jīng)為Arduino平臺(tái)探討了相同的話題。我們確定Arduino是個(gè)出色的教育工具,但由于一些限制,它無(wú)法在工業(yè)環(huán)境完全
    的頭像 發(fā)表于 03-25 09:45 ?626次閱讀
    樹莓派在自動(dòng)化控制項(xiàng)目中的<b class='flag-5'>一些</b>潛在應(yīng)用