一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

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

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

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

NEON編程中的一些常見(jiàn)優(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é)合本人的一些開(kāi)發(fā)經(jīng)歷,介紹NEON編程中的一些常見(jiàn)優(yōu)化技巧,希望能對(duì)用戶在NEON實(shí)際開(kāi)發(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%。由此可見(jiàn),降低數(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)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(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)注

    134

    文章

    9273

    瀏覽量

    373747
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5402

    瀏覽量

    122862

原文標(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)推薦

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

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

    樹(shù)莓派在自動(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 ?111次閱讀
    樹(shù)莓派在自動(dòng)化控制項(xiàng)目中的<b class='flag-5'>一些</b>潛在應(yīng)用

    嵌入式系統(tǒng)的代碼優(yōu)化與壓縮技術(shù)

    不是繼續(xù)遍歷整個(gè)數(shù)組。 函數(shù)調(diào)用優(yōu)化:頻繁的函數(shù)調(diào)用會(huì)帶來(lái)額外的開(kāi)銷(xiāo),包括參數(shù)傳遞、棧操作等。對(duì)于一些短小且頻繁調(diào)用的函數(shù),可以將其定義為內(nèi)聯(lián)函數(shù),這樣在編譯時(shí),函數(shù)代碼會(huì)直接嵌入到調(diào)用處,減少函數(shù)
    發(fā)表于 02-26 15:00

    Littrow結(jié)構(gòu)光柵系統(tǒng)的配置與優(yōu)化

    的Littrow配置 我們?cè)谶@里提供了個(gè)根據(jù)Littrow配置的光學(xué)裝置,而且通過(guò)一些編程,即使在波長(zhǎng)或光柵周期的變化下,也能保持光柵的最佳位置。 高效偏振無(wú)關(guān)傳輸光柵的分析與設(shè)計(jì) 我們演示了如何嚴(yán)格分析二元光柵的偏振相關(guān)
    發(fā)表于 12-25 15:35

    EEPROM編程常見(jiàn)錯(cuò)誤及解決方案

    EEPROM(電可擦可編程只讀存儲(chǔ)器)在編程過(guò)程可能會(huì)遇到多種錯(cuò)誤。以下是一些常見(jiàn)的EEPROM編程
    的頭像 發(fā)表于 12-16 17:08 ?3496次閱讀

    串聯(lián)電容的常見(jiàn)應(yīng)用 如何優(yōu)化串聯(lián)電路的效率

    串聯(lián)電容的常見(jiàn)應(yīng)用 串聯(lián)電容是常見(jiàn)的電路元件連接方式,其在家居、工業(yè)及電力系統(tǒng)等多個(gè)領(lǐng)域有著廣泛的應(yīng)用。以下是串聯(lián)電容的一些常見(jiàn)應(yīng)用:
    的頭像 發(fā)表于 12-02 16:35 ?3448次閱讀

    一些常見(jiàn)的動(dòng)態(tài)電路

    無(wú)論是模電還是數(shù)電,理論知識(shí)相對(duì)來(lái)說(shuō)還是比較枯燥,各種電路原理理解清楚不算容易,換種生動(dòng)形象的方式或許會(huì)增加一些趣味性,也更容易理解這些知識(shí)。下面整理了一些常見(jiàn)的電路,以動(dòng)態(tài)圖形的方
    的頭像 發(fā)表于 11-16 09:26 ?854次閱讀
    <b class='flag-5'>一些</b><b class='flag-5'>常見(jiàn)</b>的動(dòng)態(tài)電路

    編程語(yǔ)言的誤區(qū)與常見(jiàn)問(wèn)題

    誤區(qū)編程語(yǔ)言的選擇 常見(jiàn)問(wèn)題: 初學(xué)者在選擇編程語(yǔ)言時(shí),往往會(huì)被市場(chǎng)上的熱門(mén)語(yǔ)言所吸引,而忽視了自己的實(shí)際需求和興趣。 一些開(kāi)發(fā)者認(rèn)為某
    的頭像 發(fā)表于 11-15 09:35 ?597次閱讀

    分享一些常見(jiàn)的電路

    理解模電和數(shù)電的電路原理對(duì)于初學(xué)者來(lái)說(shuō)可能比較困難,但通過(guò)一些生動(dòng)的教學(xué)方法和資源,可以有效地提高學(xué)習(xí)興趣和理解能力。 下面整理了一些常見(jiàn)的電路,以動(dòng)態(tài)圖形的方式展示。 整流電路 單相橋式整流
    的頭像 發(fā)表于 11-13 09:28 ?645次閱讀
    分享<b class='flag-5'>一些</b><b class='flag-5'>常見(jiàn)</b>的電路

    ASCII碼在編程的應(yīng)用實(shí)例

    ASCII碼(American Standard Code for Information Interchange,美國(guó)信息交換標(biāo)準(zhǔn)代碼)在編程中有著廣泛的應(yīng)用。以下是一些ASCII碼在編程
    的頭像 發(fā)表于 11-10 09:43 ?1208次閱讀

    LED驅(qū)動(dòng)器應(yīng)用的一些指南和技巧

    電子發(fā)燒友網(wǎng)站提供《LED驅(qū)動(dòng)器應(yīng)用的一些指南和技巧.pdf》資料免費(fèi)下載
    發(fā)表于 09-25 11:35 ?0次下載
    LED驅(qū)動(dòng)器應(yīng)用的<b class='flag-5'>一些</b>指南和技巧

    關(guān)于一些有助于優(yōu)化電源設(shè)計(jì)的新型材料

    眾所周知,人們對(duì)更高電源效率的追求正在推動(dòng)性能的全方位提升。材料科學(xué)的進(jìn)步對(duì)于優(yōu)化電源設(shè)計(jì)和開(kāi)發(fā)更高效、更緊湊和更可靠的解決方案發(fā)揮著關(guān)鍵作用。下文列出了一些有助于優(yōu)化電源設(shè)計(jì)的新材料。
    的頭像 發(fā)表于 08-29 15:26 ?649次閱讀

    二進(jìn)制處理一些技巧

    在二進(jìn)制和十進(jìn)制的處理,有時(shí)候一些小技巧是很有用的。 1、把十進(jìn)制數(shù)轉(zhuǎn)換成二進(jìn)制數(shù) (1)在MATLAB中有個(gè)函數(shù)dec2bin,可以把正整數(shù)轉(zhuǎn)換為2進(jìn)制 (2)對(duì)于負(fù)數(shù)有這樣
    的頭像 發(fā)表于 07-05 11:51 ?810次閱讀

    聚徽觸控 - 教學(xué)體機(jī)常見(jiàn)故障及解決辦法

    教學(xué)體機(jī)在使用過(guò)程可能會(huì)遇到多種故障,以下是一些常見(jiàn)的故障及解決辦法:
    的頭像 發(fā)表于 07-01 15:44 ?1292次閱讀

    PCB設(shè)計(jì)常見(jiàn)問(wèn)題有哪些?

    板)設(shè)計(jì)是個(gè)至關(guān)重要的環(huán)節(jié)。個(gè)優(yōu)秀的PCB設(shè)計(jì)不僅能夠保證電子產(chǎn)品的穩(wěn)定運(yùn)行,還能提高產(chǎn)品的外觀和性能。然而,很多設(shè)計(jì)師在PCB設(shè)計(jì)中會(huì)遇到一些常見(jiàn)的問(wèn)題,這些問(wèn)題可能會(huì)導(dǎo)致設(shè)計(jì)延
    的頭像 發(fā)表于 05-23 09:13 ?1221次閱讀
    PCB設(shè)計(jì)<b class='flag-5'>中</b>的<b class='flag-5'>常見(jiàn)</b>問(wèn)題有哪些?