国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

NEON編程中的一些常見優化技巧

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

掃碼添加小助手

加入工程師交流群

1.簡介

讀過上一篇文章“ARM NEON快速上手指南”之后,相信你已經對ARM NEON編程有了基本的認識。但在真正利用ARM NEON優化程序性能時,還有很多編程技巧和注意事項。本文將結合本人的一些開發經歷,介紹NEON編程中的一些常見優化技巧,希望能對用戶在NEON實際開發中有些借鑒意義。

2.NEON優化技術

在利用NEON優化程序時,有下述幾項比較通用的優化技巧。

2.1 降低數據依賴性

在ARM v7-A NEON指令通常需要3~9個指令周期,NEON指令比ARM指令需要更多周期數。因此,為了減少指令延時,最好避免將當前指令的目的寄存器當作下條指令的源寄存器。如下例所示:

// 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實現一
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實現二
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實現一中,我們把目的寄存器立刻當作源寄存器;在NEON實現二中,我們重新排布了指令,并給予目的寄存器盡量多的延時。經過測試實現二比實現一快30%。由此可見,降低數據依賴性對于提高程序性能有重要意義。一個好消息是編譯器能自動調整NEON intrinsics以降低數據依賴性。這個利用NEON intrinsics的一個很大優勢。

2.2 減少跳轉

NEON指令集沒有跳轉指令,當需要跳轉時,我們需要借助ARM指令。在ARM處理器中,分支預測技術被廣泛使用。但是一旦分支預測失敗,懲罰還是比較高的。因此我們最好盡量減少跳轉指令的使用。其實,在有些情況下,我們可以用邏輯運算來代替跳轉,如下例所示:

// C實現
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實現
//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指令集提供了下列指令來幫助用戶實現上述邏輯實現:

? VCEQ, VCGE, VCGT, VCLE, VCLT……

? VBIT, VBIF, VBSL……

減少跳轉,不僅僅是在NEON中使用的技巧,是一個比較通用的問題。即使在C程序中,這個問題也是值得注意的。

2.3 其它技巧

在ARM NEON編程時,一種功能有時有多種實現方式,但是更少的指令不總是意味著更好的性能,要依據測試結果和profiling數據,具體問題具體分析。下面列出來我遇到的一些特殊情況。2.3.1 浮點累加指令通常情況下,我們會用VMLA/VMLS來代替VMUL + VADD/ VMUL + VSUB,這樣使用較少的指令,完成更多的功能。但是與浮點VMUL相比,浮點VMLA/VMLS具有更長的指令延時,如果在指令延時中間不能插入其它計算的情況下,使用浮點VMUL + VADD/ VMUL + VSUB反而具有更好的性能。一個真實例子就是Ne10庫函數的浮點FIR函數。代碼片段如下所示:

實現1:在兩條VMLA指令之間,僅有VEXT指令。而根據指令延時表,VMLA需要9個周期。

實現2:對于qAcc0,依然存在指令延時。但是VADD/VMUL只需要5個周期。下列代碼中周期n粗略地表示了指令執行需要的周期數。與實現1相比,實現2節省了6個周期。性能測試也表明實現2具有更好的性能。

實現 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
得到最終結果 qAcc0需要36個指令周期。
實現 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
得到最終結果 qAcc0需要24個指令周期。
與實現1相比,三條VADD指令需要6個發射指令周期。總共需要 30個指令周期。

modules/dsp/NE10_fir.neon.s:line 195

指令延時請參考下表:

Name Format Cycles Result
VADD/VSUB/VMUL Qd,Qn,Dm 2 5
VMLA/VMLS Qd,Qn,Dm 2 9

表格來源于Cortex-A9 NEON Media Processing Engine Revision: r4p1 Technical Reference Manual: 3.4.8。

表格中:? Cycles:指令發射時間

? Result:指令執行時間

2.4 小結

總結起來,NEON的優化技巧主要有以下幾點

? 盡量利用指令執行延時,合理安排指令順序

? 少用跳轉

? 注意cache命中率

審核編輯:郭婷


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • ARM
    ARM
    +關注

    關注

    135

    文章

    9552

    瀏覽量

    391841
  • 寄存器
    +關注

    關注

    31

    文章

    5608

    瀏覽量

    129966

原文標題:Arm NEON學習(二)優化技術

文章出處:【微信號:Ithingedu,微信公眾號:安芯教育科技】歡迎添加關注!文章轉載請注明出處。

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    爬壁機器人磁鐵的一些常見問題

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

    CW32系統有哪些常見問題?

    在CW32系統,可能會遇到一些常見問題,包括但不限于: 重復定義函數:例如在a.c里定義了函數void func(),在b.c里也定義了個void func()。這會導致編譯時出
    發表于 12-15 06:47

    關于六類網線一些問題的解答

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

    貼片電容精度J±5%的一些詳細知識

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

    蜂鳥E203的浮點指令集F的一些實現細節

    周期。 總結 本文介紹的內容是為了完成基礎功能:對蜂鳥E203 RISC-V內核的微架構實現進行優化,在添加F拓展的過程一些記錄。
    發表于 10-24 08:57

    Vivado浮點數IP核的一些設置注意點

    : 總結 本文介紹的內容是為了完成基礎功能:對蜂鳥E203 RISC-V內核的微架構實現進行優化,在添加F拓展的過程一些記錄。
    發表于 10-24 06:25

    在Ubuntu20.04系統訓練神經網絡模型的一些經驗

    本帖欲分享在Ubuntu20.04系統訓練神經網絡模型的一些經驗。我們采用jupyter notebook作為開發IDE,以TensorFlow2為訓練框架,目標是訓練個手寫數字識別的神經網絡
    發表于 10-22 07:03

    射頻工程師需要知道的一些常見轉接頭

    ,是由于轉接頭的損壞造成的,而且有些接頭的連接固定的方式不對,每次修好的儀器,過去后客戶又按照他們原來的方式去擰緊了。特別是在一些生產型的企業,由于操作人員流動性比較
    的頭像 發表于 08-06 17:39 ?1219次閱讀
    射頻工程師需要知道的<b class='flag-5'>一些</b><b class='flag-5'>常見</b>轉接頭

    如何優化編程電源控制環路參數?

    時環路相位裕度僅25°,輸出電壓振蕩(頻率10kHz)。 優化措施:在補償網絡增加個小電容(10pF),引入個高頻極點衰減振蕩;調整補償電容CCOMP?從10nF增至22nF,提
    發表于 07-02 15:56

    在低功耗藍牙產品開發的過程,會涉及到一些參數的選擇和設定,這些參數是什么意思,該如何設定呢?(藍牙廣播)

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

    HarmonyOS優化應用內存占用問題性能優化

    應用開發過程中注重內存管理,積極采取措施來減少內存占用,以優化應用程序的性能和用戶體驗。 HarmonyOS提供了一些內存管理的工具和接口,幫助開發者有效地管理內存資源: onMemoryLevel接口
    發表于 05-21 11:27

    Debian和Ubuntu哪個好一些

    兼容性對比Debian和Ubuntu哪個好一些,并為您揭示如何通過RAKsmart服務器釋放Linux系統的最大潛能。
    的頭像 發表于 05-07 10:58 ?1134次閱讀

    PCBA加工返修全攻略:常見問題網打盡

    現代PCBA工藝已經非常成熟,但在生產和組裝過程依然難免會遇到一些質量問題,導致返修工作增加。為了解決這些問題,并提高產品的最終質量,本文將詳細探討PCBA返修中常見的問題及其對應的解決方案。 PCBA
    的頭像 發表于 04-02 18:00 ?976次閱讀

    樹莓派在自動化控制項目中的一些潛在應用

    自動化控制項目中的一些潛在應用。之前,我們已經為Arduino平臺探討了相同的話題。我們確定Arduino是個出色的教育工具,但由于一些限制,它無法在工業環境完全
    的頭像 發表于 03-25 09:45 ?614次閱讀
    樹莓派在自動化控制項目中的<b class='flag-5'>一些</b>潛在應用

    VirtualLab Fusion應用:使用自定義的評價函數優化高NA分束器

    嚴格的后優化,至少建議進行嚴格的分析。在這個用例,使用奇數衍射級對典型的二元1:6分束器執行這樣嚴格的評估。為此,對初始系統的結構進行了參數化,并通過可編程光柵分析器定義了組自定義
    發表于 03-07 08:54