在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > ARM處理器NEON編程及優(yōu)化技巧——處理剩余的元素

            ARM處理器NEON編程及優(yōu)化技巧——處理剩余的元素

            作者: 時(shí)間:2016-11-10 來(lái)源:網(wǎng)絡(luò) 收藏
            ARM的NEON協(xié)處理器技術(shù)是一個(gè)64/128-bit的混合SIMD架構(gòu),用于加速包括視頻編碼解碼、音頻解碼編碼、3D圖像、語(yǔ)音和圖像等多媒體和信號(hào)處理應(yīng)用。本文主要介紹如何使用NEON的匯編程序來(lái)寫SIMD的代碼,包括如何開始NEON的開發(fā),如何高效的利用NEON。首先會(huì)關(guān)注內(nèi)存操作,即如何變更指令來(lái)靈活有效的加載和存儲(chǔ)數(shù)據(jù)。接下來(lái)是由于SIMD指令的應(yīng)用而導(dǎo)致剩下的若干個(gè)單元的處理,然后是用一個(gè)矩陣乘法的例子來(lái)說(shuō)明用NEON來(lái)進(jìn)行SIMD優(yōu)化,最后關(guān)注如何用NEON來(lái)優(yōu)化各種各樣的移位操作,左移或者右移以及雙向移位等。本節(jié)主要介紹當(dāng)輸入的數(shù)據(jù)大小不是一個(gè)向量大小的整數(shù)倍時(shí),怎么處理剩余的幾個(gè)元素,如把元素補(bǔ)齊到向量大小的整數(shù)倍的修復(fù)處理、重疊處理方式和單個(gè)元素處理方式。

            關(guān)鍵字: ARM NEON Cortex-A8 cache 對(duì)齊

            本文引用地址:http://www.biyoush.com/article/201611/317425.htm

            剩余的元素Leftovers

            通常NEON會(huì)向量處理從4個(gè)到16個(gè)元素長(zhǎng)度的數(shù)據(jù),如果你發(fā)現(xiàn)你的數(shù)組不是這個(gè)這個(gè)長(zhǎng)度的整數(shù)倍,你就需要單獨(dú)處理那些剩下來(lái)的幾個(gè)元素。如你每次可以使用NEON來(lái)加載處理并存儲(chǔ)8個(gè)元素的數(shù)據(jù),但是你的數(shù)組有21個(gè)元素,你就需要先迭代兩次,然后第三次,你只剩下5個(gè)元素,此時(shí)應(yīng)該如何處理呢?

            Fixing Up修復(fù)處理方式

            有三種處理方式來(lái)處理剩下來(lái)的元素,這些方法的需求、性能和代碼大小不同,下面順序介紹,從速度最快的方法開始。

            Larger Arrays更大的數(shù)組

            如果改變你要處理的數(shù)組大小,比如增加數(shù)組大小到向量大小的整數(shù)倍,這樣就能在最后一次數(shù)據(jù)處理時(shí)也按照向量大小處理而不會(huì)把臨近的數(shù)據(jù)損壞。如上面的例子里,把數(shù)組大小增加到24個(gè)元素,這樣就能用NEON用3次迭代完成所有的數(shù)據(jù)處理而不會(huì)損壞周邊數(shù)據(jù)。

            圖1. 填補(bǔ)數(shù)組到向量的整數(shù)個(gè)大小

            注意事項(xiàng)Notes

            • 分配更大的數(shù)組需要更多的存儲(chǔ)空間,這會(huì)增加相當(dāng)大的空間如果包含非常多的短數(shù)組;
            • 在數(shù)組后面填補(bǔ)的數(shù)據(jù)元素需要初始化為一個(gè)不會(huì)影響到結(jié)果的值,例如你要做加法,那這個(gè)新元素需要初始化為0以影響計(jì)算結(jié)果。
            • 一些情況下,可能沒(méi)法初始化填充的數(shù)據(jù),無(wú)論填充什么都會(huì)影響計(jì)算的結(jié)果;

            Code Fragment代碼片段實(shí)例

            @ r0 是輸入的數(shù)組指針;

            @ r1 是輸出數(shù)組指針;

            @ r2 是數(shù)組數(shù)據(jù)的長(zhǎng)度;

            假設(shè)數(shù)組長(zhǎng)度大于0,是向量大小的整數(shù)倍,并且大于或者等于數(shù)組的長(zhǎng)度;

            add r2, r2, #7 @ 數(shù)據(jù)長(zhǎng)度加上向量長(zhǎng)度-1

            lsr r2, r2, #3 @ 把數(shù)組長(zhǎng)度變成向量個(gè)數(shù),即除以向量大小8

            loop:

            subs r2, r2, #1 @ 減少循環(huán)計(jì)數(shù)器個(gè)數(shù)

            vld1.8 {d0}, [r0]! @ 從數(shù)組加載8個(gè)元素,從地址r0到寄存器d0,然后更新地址寄存器r0到下一個(gè)向量地址;

            ...

            ... @ 處理在d0寄存器的數(shù)據(jù)

            ...

            vst1.8 {d0}, [r1]! @ 把8個(gè)結(jié)果元素保存到輸出數(shù)組,更新地址r1到下一個(gè)向量

            bne loop @ 如果r2不等于0,繼續(xù)循環(huán)

            Overlapping重疊計(jì)算

            如果進(jìn)行數(shù)據(jù)處理的操作合適的話,可以考慮把剩余部分的元素通過(guò)重疊計(jì)算的方式處理,這就會(huì)把某些重疊部分的元素計(jì)算兩次。如下面的例子里,第一次迭代計(jì)算元素0到7,第一次計(jì)算5到12,第三次計(jì)算13到20。從而第一次計(jì)算和第二次計(jì)算重疊的元素5到7就被計(jì)算了兩次。

            arm.com/index.php?app=core&module=attach§ion=attach&attach_rel_module=blogentry&attach_id=419" rel="nofollow" >

            圖2. 重疊向量,在橙色區(qū)域的數(shù)據(jù)計(jì)算兩次

            Notes需要事項(xiàng)

            • 重疊處理只適用于需要處理的數(shù)組長(zhǎng)度不會(huì)隨著每次迭代而改變的情況,但不適用于每次迭代結(jié)果改變的情況,如累加計(jì)算,這樣重疊部分的數(shù)據(jù)會(huì)被計(jì)算兩次;
            • 數(shù)組內(nèi)元素的個(gè)數(shù)至少大于一次完整迭代的向量大?。?/li>

            Code Fragment代碼片段實(shí)例

            @ r0 是輸入的數(shù)組指針;

            @ r1 是輸出數(shù)組指針;

            @ r2 是數(shù)組數(shù)據(jù)的長(zhǎng)度;

            假設(shè)數(shù)據(jù)操作冪等,并且數(shù)組長(zhǎng)度大于等于一個(gè)向量大小長(zhǎng)度。

            ands r3, r2, #7 @ 計(jì)算每次處理完整個(gè)向量后剩余元素個(gè)數(shù),使用與操作

            beq loopsetup @ 如果剩余元素個(gè)數(shù)為0,則數(shù)組長(zhǎng)度是整數(shù)個(gè)向量大小,不用重疊計(jì)算,單獨(dú)處理第一個(gè)元素部分

            vld1.8 {d0}, [r0], r3 @ 加載數(shù)組第一個(gè)向量,然后更新數(shù)組大小為剩余元素個(gè)數(shù)r3內(nèi)保持

            ...

            ... @ 處理d0寄存器內(nèi)的輸入數(shù)據(jù)

            ...

            vst1.8 {d0}, [r1], r3 @ 保持8個(gè)元素到輸出數(shù)組,更新指針,然后開始處理循環(huán)

            loopsetup:

            lsr r2, r2, #3 @ 把數(shù)組長(zhǎng)度除以8,計(jì)算循環(huán)迭代次數(shù),若干元素跟第一次迭代的重疊

            loop:

            subs r2, r2, #1 @ 減少循環(huán)計(jì)數(shù)器個(gè)數(shù)

            vld1.8 {d0}, [r0]! @ 從數(shù)組加載8個(gè)元素,從地址r0到寄存器d0,然后更新地址寄存器r0到下一個(gè)向量地址;

            ...

            ... @ 處理在d0寄存器的數(shù)據(jù)

            ...

            vst1.8 {d0}, [r1]! @ 把8個(gè)結(jié)果元素保存到輸出數(shù)組,更新地址r1到下一個(gè)向量

            bne loop @ 如果r2不等于0,繼續(xù)循環(huán)

            單個(gè)元素的計(jì)算過(guò)程Single Elements

            NEON提供了能處理向量里的單一元素的加載和存儲(chǔ)指令,用這些指令,你能加載包含一個(gè)元素的部分向量,處理它然后把結(jié)果保存到內(nèi)存。如下面的例子,前兩次的迭代處理跟前面類似,處理元素0到7以及8到15,剩下的5個(gè)元素可以在第三次迭代處理,加載處理并存儲(chǔ)單一的元素。

            圖3. 處理單一的元素實(shí)例

            注意事項(xiàng)

            • 這種方法比前面的兩種方法速度要慢,每個(gè)元素的處理都需要單獨(dú)進(jìn)行;
            • 這種的剩余元素處理方法需要兩個(gè)迭代循環(huán),第一個(gè)處理向量的循環(huán),還有處理剩余元素的循環(huán),這會(huì)增加代碼大??;
            • NEON的單一元素加載只改變目標(biāo)元素的值,而保留其他的元素不變,如果你向量計(jì)算的指令會(huì)在一個(gè)向量間反復(fù)計(jì)算,如VPADD,這些寄存器需要在第一個(gè)元素加載時(shí)初始化。

            代碼片段

            @ r0 是輸入的數(shù)組指針;

            @ r1 是輸出數(shù)組指針;

            @ r2 是數(shù)組數(shù)據(jù)的長(zhǎng)度;

            lsrs r3, r2, #3 @ 計(jì)算向量循環(huán)迭代的次數(shù)

            beq singlesetup @ 如果沒(méi)有完整的一次迭代向量計(jì)算,則跳轉(zhuǎn)到單一元素處理循環(huán)

            @ 處理向量循環(huán)

            vectors:

            subs r3, r3, #1 @減少循環(huán)計(jì)數(shù)器個(gè)數(shù)

            vld1.8 {d0}, [r0]! @ 從數(shù)組加載8個(gè)元素,從地址r0到寄存器d0,然后更新地址寄存器r0到下一個(gè)向量地址;

            ...

            ... @ 處理在d0寄存器的數(shù)據(jù)

            ...

            vst1.8 {d0}, [r1]! @ 把8個(gè)結(jié)果元素保存到輸出數(shù)組,更新地址r1到下一個(gè)向量

            bne vectors @如果r3不等于0,繼續(xù)循環(huán)

            singlesetup:

            ands r3, r2, #7 @ 計(jì)算單一元素迭代的次數(shù)

            beq exit @ 如果單一元素計(jì)算次數(shù)為0,則跳轉(zhuǎn)退出

            @ 處理單一元素的循環(huán)

            singles:

            subs r3, r3, #1 @減少循環(huán)計(jì)數(shù)器個(gè)數(shù)

            vld1.8 {d0[0]}, [r0]! @從數(shù)組加載單一元素,從地址r0到寄存器d0,然后更新地址寄存器r0到下一個(gè)地址

            ...

            ... @ 處理在d0[0]內(nèi)的輸入數(shù)據(jù)

            ...

            vst1.8 {d0[0]}, [r1]! @ 保存單一元素結(jié)果到輸出數(shù)組,更新指針地址

            bne singles @如果r3不等于0,繼續(xù)循環(huán)

            exit:

            其他的考慮

            在開始處還是結(jié)束處

            用重疊計(jì)算的方式以及用單一元素處理都能在數(shù)組開始處或者結(jié)束處處理,因而代碼就要考慮兩種實(shí)現(xiàn)方式哪種效率高些,哪個(gè)更適合你的系統(tǒng)應(yīng)用。

            數(shù)據(jù)對(duì)齊

            加載或者存儲(chǔ)指令的地址應(yīng)該對(duì)齊到cache line,這樣內(nèi)存的訪問(wèn)效率更高。這樣就需要在Cortex-A8的處理器上至少16字對(duì)齊,如果你不能把輸入和輸出數(shù)組的起始地址對(duì)齊到16字,你就必須處理開始和結(jié)束數(shù)據(jù)處理的那若干個(gè)元素以使得后續(xù)的數(shù)據(jù)訪問(wèn)是對(duì)齊到cache行的。為了使用內(nèi)存對(duì)齊的方式訪問(wèn)內(nèi)存以提高速度,你在使用NEON指令時(shí)需要使用諸如64或者128或者256等地址限定符來(lái)制定加載和存儲(chǔ)指令。你可以比較發(fā)出一個(gè)對(duì)齊的訪問(wèn)和非對(duì)齊訪問(wèn)的性能,以下是始終周期的頁(yè)面Cortex-A8 TRM.

            使用ARM來(lái)做修復(fù)

            在使用單個(gè)元素處理的情況下,你可以使用ARM指令來(lái)進(jìn)行單個(gè)元素的操作,但是同時(shí)使用ARM和NEON來(lái)訪問(wèn)同一塊區(qū)域的內(nèi)存會(huì)降低系統(tǒng)性能,因?yàn)閺腁RM的流水線發(fā)出的寫操作會(huì)在NEON的流水線完成之后才能進(jìn)行。因而你要盡量的避免在ARM和NEON的代碼里同時(shí)訪問(wèn)同一塊內(nèi)存區(qū)域(當(dāng)然,這同一塊內(nèi)存區(qū)域也對(duì)應(yīng)于同一個(gè)cache line)



            評(píng)論


            技術(shù)專區(qū)

            關(guān)閉