新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 在Cortex-A8平臺下memcpy ARM/NEON匯編性能的測試

        在Cortex-A8平臺下memcpy ARM/NEON匯編性能的測試

        作者: 時間:2016-11-10 來源:網絡 收藏
        本文介紹了基于ARMv7架構的Cortex-A8芯片(FreeScale i.MX51 / i.MX53/QualComm msm8x50 / msm7x30/Samsung s5pc100 / s5pc110/TI omap 3430 / omap 3730芯片)上采用C語言、ARM匯編和NEON匯編實現的memcpy的性能對比,并輸入分析了NEON指令(不同處理器的NEON內存位寬從64-bit到128-bit不等)和cache的預取preload(preload engine指令)對性能的影響。最終結論表明1.在拷貝塊大小block size = 512B ~ 32K之間,有一個性能高臺,block size = 256K也有一個性能的轉折。這個特性體現了芯片32KB L1 / 256KB L2 cache的影響;2. NEON指令的性能總是要高于ARM指令的性能。隨著發展ARM/NEON指令之間性能差在縮小。交替使用ARM/NEON指令,性能往往要差于NEON版本;3.如果沒有很好的模型設計,軟件去干預cache的使用,很容易會造成性能的惡化; 4.在fit in cache條件下,Snapdragon平臺有最好的性能; 5.在out of cache條件下,s5pc110有最好的性能; 6.在同一個硬件平臺下,超頻對memory性能影響很小; 7.同一種的實現,在不同的硬件平臺上都有不同的表現。沒有一種實現在所有平臺上是最好的。
        1. 前言

          在C run time library中,memcpy是重要的函數,對應用軟件的性能有著重要的影響。ARM芯片發展到Cortex-A8[1][2]架構,不但頻率有了很大提升,而且架構設計有了很大地改進。其中增加的NEON指令,是類似于原先X86平臺下的MMX指令,是為多媒體而設計。但因為這類指令一次可以處理64-bit數據,對memcpy函數性能提升也很有幫助。本文主要是測試采用NEON[2]指令的多種memcpy實現,探討NEON指令和預取(preload)指令對性能的影響,以及在芯片優化和工藝進步后,這些影響的變化趨勢。同時希望芯片設計人員在了解軟件實現的基礎上,給予一個知其然,也知其所以然的解釋,進而指導進一步提高性能的方向。

          本文引用地址:http://www.104case.com/article/201611/317414.htm
        2. 平臺介紹

          本次的測試平臺來源于筆者工作項目中接觸到的Cortex-A8平臺。見下面列表:

        • FreeScale i.MX51 / i.MX53
        • QualComm msm8x50 / msm7x30
        • Samsung s5pc100 / s5pc110
        • TI omap 3430 / omap 3730
        1. i.MX5 family

          i.MX5 family的介紹見[6][7]。其中i.MX535可以運行在800MHZ / 1000MHZ兩種頻率上。

        • i.MX515
          • freq: 800MHZ
          • cache size: 32KB/32KB I/D Cache and 256KB L2 Cache
          • cache line: 64-bit wide(NEON), 64-byte / line
        • i.MX535
        • freq: 800MHZ / 1000MHZ
        • cache size: 32KB/32KB I/D Cache and 256KB L2 Cache
        • cache line: 64-bit wide(NEON), 64-byte / line
        1. Snapdragon family

          Snapdragon的介紹見[8][9][10]。其中msm7x30可以運行在800MHZ / 1000MHZ兩種頻率上。此外Snapdragon cache特別之處是128-bit wide(NEON), 128-byte / line。標準Cortex-A8中,該數值為64-bit wide(NEON), 64-byte / line。這對性能有較大影響。

        • msm8x50
          • freq: 1000MHZ
          • cache size: 32KB/32KB I/D Cache and 256KB L2 Cache
          • cache line: 128-bit wide(NEON), 128-byte / line
        • msm7x30
          • freq: 800MHZ / 1000MHZ
          • cache size: 32KB/32KB I/D Cache and 256KB L2 Cache
          • cache line: 128-bit wide(NEON), 128-byte / line
        1. s5pc family

          s5pc family參考平臺見[11]。

        • s5pc100
          • freq: 665MHZ
          • cache size: 32KB/32KB I/D Cache and 256KB L2 Cache
          • cache line: 64-bit wide(NEON), 64-byte / line
        • s5pc110
          • freq: 1000MHZ
          • cache size: 32KB/32KB I/D Cache and 512KB L2 Cache
          • cache line: 64-bit wide(NEON), 64-byte / line
        1. omap3 family

          omap3 family參考平臺見[12][13][14]。

        • omap3430
          • freq: 550MHZ
          • cache size: 16KB/16KB I/D Cache and 256KB L2 Cache
          • cache line: 64-bit wide(NEON), 64-byte / line
        • omap3730
          • freq: 1000MHZ
          • cache size: 32KB/32KB I/D Cache and 256KB L2 Cache
          • cache line: 64-bit wide(NEON), 64-byte / line
        1. memcpy實現介紹

          memcpy的實現在ARM平臺上的發展有3類版本:

        2. C語言版本
        3. ARM匯編版本
        4. NEON匯編版本

          ARM公司的文檔[4]對memcpy的實現有很好描述。有人[5][19][20]還進一步闡述了實現原理和技巧。簡述如下:

        • NEON指令一次可以處理64-bit數據,效率更高。
        • NEON架構與L1/L2 cache都有直連,在OS層級enable后,可以獲得更好的性能。
        • ARM / NEON的pipeline有可能異步處理,交替使用ARM / NEON指令有可能獲得更好的性能。
        • 在一次循環中,用盡可能多的寄存器copy更多的數據,保證pipeline有更好的效率。目前一次最大處理塊為128-byte。
        • 對cache的操作有講究。
          • memcpy屬于一次掃瞄無回溯的操作,對于cache采用預取(preload)策略可以提高hit rate。所以匯編版本中一定會使用pld指令提示ARM預先把cache line填充好。
          • pld指令中的offset很有講究。一般為64-byte的倍數。在ARMv5TE平臺是一個循環用一個pld指令。在Cortex-A8平臺上速度更快,需要一個循環用2~3個pld指令填充cache line。這樣一個循環消費2~3個時鐘周期換得cache hit rate提高,效果是值得的。
          • 進一步的,Cortex-A8架構提供了preload engine指令,可以讓軟件更深地影響cache,以便讓cache hit rate得到提高。不過要在用戶空間使用ple指令,需要在OS中打補丁開放權限。

        1. C語言版本

          C語言版本主要是做對比。采用兩個實現:

        2. 32-bit wide copy。后面標記為in32_cpy。
        3. 16-byte wide copy。后面標記為vec_cpy。這個實現的技巧是采用gcc的向量擴展"__attribute__ ((vector_size(16)))",在C語言層級實現16-byte wide copy,將具體實現交給編譯器。

          值得注意的事情是,編譯器不會主動插入pld指令。因為編譯器無法判斷應用對內存的訪問模式。

        4. ARM匯編版本

          ARM匯編版本也主要是做對比。采用兩個實現:

        5. Siarhei Siamashka實現[15]。后面標記為arm9_memcpy。他是為Nokia N770做的優化。
        6. Nicolas Pitre實現[16]。后面標記為armv5te_memcpy。這是目前glibc里面缺省的arm memcpy實現。
        7. NEON匯編版本

          NEON匯編版本采用四個實現:

        8. M?ns Rullg?rd實現[19]。這是一個128-byte-align block的最簡單的實現。沒有判斷不是128-byte align的情況。因此不是實用的版本。但通過這類實現,可以考察memcpy性能的極限。他總共提供4種實現。
        9. 全ARM匯編的實現。后面標記為memcpy_arm。此外,筆者還將其中的pld指令去掉,做為對比試驗,考察pld指令的影響。后面標記為memcpy_arm_nopld。
        10. 全NEON匯編的實現。后面標記為memcpy_neon。此外,筆者還將其中的pld指令去掉,做為對比試驗,考察pld指令的影響。后面標記為memcpy_neon_nopld。
        11. ARM / NEON指令交替使用的實現。后面標記為memcpy_armneon。此外,筆者還將其中的pld指令去掉,做為對比試驗,考察pld指令的影響。后面標記為memcpy_armneon_nopld。
        12. ple + NEON的實現。后面標記為memcpy_ple_neon。此外,筆者還將其中的NEON指令換成ARM指令,做為對比試驗,考察ple指令對ARM/NEON指令的影響。后面標記為memcpy_ple_arm。因為這個實現需要對linux kernel打補丁,在omap3430平臺上沒有成功。在Snapdragon平臺上更換kernel有些麻煩,所以也沒有測試。
        13. CodeSourcery實現[17]。這是CodeSourcery toolchain中的glibc里面的實現。也分兩種實現。
        14. ARM實現。后面標記為memcpy_arm_codesourcery。筆者還將其中的pld指令去掉,做為對比試驗,考察pld指令的影響。后面標記為memcpy_arm_codesourcery_nopld。
        15. NEON實現。后面標記為memcpy_neon_codesourcery。這也是Android bionic里面采用的NEON實現。筆者還將其中的pld指令去掉,做為對比試驗,考察pld指令的影響。后面標記為memcpy_neon_codesourcery_nopld。
        16. QualComm實現[18]。后面標記為memcpy_neon_qualcomm。這是QualComm在Code Aurora Forum中為Snapdragon平臺開發的優化版本。主要是對8660/8650A平臺的優化。這個版本的特點是針對L2 cache line size=128bytes而設計,pld offset設置得特別大。結果在其它Cortex-A8平臺上沒有效果。所以筆者將pld offset改為M?ns Rullg?rd實現的數值。筆者還將其中的pld指令去掉,做為對比試驗,考察pld指令的影響。后面標記為memcpy_neon_qualcomm_nopld。
        17. Siarhei Siamashka實現[20]。后面標記為memcpy_neon_siarhei。這是Siarhei Siamashka向glibc提交的NEON版本,沒有被glibc采納。但是在MAEMO項目中得到采用。這個版本的特點是pld offset是從小到大增長的,以期望適應block size的變化。
        18. 測試方案介紹

          測試方案十分簡單。參考了movial memory tester的實現[21]。執行步驟如下:

        19. 先對每個實現進行正確性的驗證。主要方法是以隨機的block size & offset,填充隨機的內容,然后執行memcpy操作,然后再用系統的memcmp函數對兩塊內存做校驗。
        20. 然后對每個實現以不同的block size調用400次。如果total copy size < 1MB,則增加count直到滿足要求。對總操作計時。
        21. 以total copy size / total copy time公式計算memcpy bandwidth。

          上述提到的block size = 2^n ( 7 <= n <= 23 )。

          此外,這個測試程序運行在openembedded-gpe軟件系統中。QualComm / Samsung硬件平臺只提供Android軟件系統,要更換到GPE系統有些麻煩,則采用chroot方式進行測試。不論是哪種軟件平臺,都是進入到圖形系統后,靜置,等待黑屏,然后再進行測試。

          下表是運行環境的統計。

          硬件平臺

          軟件環境

          imx51 800MHZ

          openembedded-gpe

          imx53 1000MHZ

          openembedded-gpe

          imx53 800MHZ

          openembedded-gpe

          msm7230 1000MHZ

          Android + chroot

          msm7230 800MHZ

          Android + chroot

          msm8250 1000MHZ

          Android + chroot

          omap3430 550MHZ

          openembedded-gpe

          omap3730 1000MHZ

          openembedded-gpe

          s5pc100 665MHZ

          Android + chroot

          s5pc110 1000MHZ

          Android + chroot

          下表是測試項目的統計。

          實現方案

          i.MX51

          i.MX53

          Snapdragon

          s5pc1xx

          omap3430

          omap3730

          int32_cpy

          YES

          YES

          YES

          YES

          YES

          YES

          vec_cpy

          YES

          YES

          YES

          YES

          YES

          YES

          arm9_memcpy

          YES

          YES

          YES

          YES

          YES

          YES

          armv5te_memcpy

          YES

          YES

          YES

          YES

          YES

          YES

          memcpy_arm

          YES

          YES

          YES

          YES

          YES

          YES

          memcpy_arm_nopld

          YES

          NO

          YES

          YES

          YES

          YES

          memcpy_neon

          YES

          YES

          YES

          YES

          YES

          YES

          memcpy_neon_nopld

          YES

          NO

          YES

          YES

          YES

          YES

          memcpy_armneon

          YES

          YES

          YES

          YES

          YES

          YES

          memcpy_ple_arm

          YES

          YES

          N/A

          YES

          N/A

          YES

          memcpy_ple_neon

          YES

          YES

          N/A

          YES

          N/A

          YES

          memcpy_arm_codesourcery

          YES

          YES

          YES

          YES

          YES

          YES

          memcpy_arm_codesourcery_nopld

          YES

          NO

          YES

          YES

          YES

          YES

          memcpy_neon_codesourcery

          YES

          YES

          YES

          YES

          YES

          YES

          memcpy_neon_codesourcery_nopld

          YES

          NO

          YES

          YES

          YES

          YES

          memcpy_neon_qualcomm

          YES

          YES

          YES

          YES

          YES

          YES

          memcpy_neon_qualcomm_nopld

          YES

          NO

          YES

          YES

          YES

          YES

          memcpy_neon_siarhei

          YES

          YES

          YES

          YES

          YES

          YES

          注1:因為i.MX53 EVK板子發生故障,未能測試所有no pld的測試項。

          注2:在給omap3430打開preload engine后,測試產生非法指令錯,未能測試ple的測試項。

          注3:要替換Snapdragon kernel有些麻煩,未能測試ple的測試項。

        22. 測試結果與分析

          下面的圖表限于頁面大小不能很好地顯示細節。具體的數據和大圖可到數據表文檔中查看。

        23. 各個硬件平臺上各種實現的表現

        24. imx51 800MHZ

        25. imx53 1000MHZ

        26. imx53 800MHZ

        27. msm7230 1000MHZ

        28. msm7230 800MHZ

        29. msm8250 1000MHZ

        30. omap3430 550MHZ

        31. omap3730 1000MHZ

        32. s5pc100 665MHZ

        33. s5pc110 1000MHZ

          1. 小結

        34. 在block size = 512B ~ 32K之間,有一個性能高臺,block size = 256K也有一個性能的轉折。
        35. 這個特性體現了32KB L1 / 256KB L2 cache的影響。
        36. 小于512B的性能不佳,可能與函數調用,函數開始的塊對齊技巧造成的損耗有關,也可能與block size太小,cache沒有準備好函數就結束了有關。
        37. 文檔[]對memcpy的實現還是有指導意義的。但隨著芯片內部的優化和工藝的提升,有些規則發生了變化。
        38. NEON指令的性能總是要高于ARM指令的性能。但交替使用ARM/NEON指令并不總是帶來性能的提升。隨著發展ARM/NEON指令之間性能差在縮小。
        39. pld指令的作用越來越小。在較老的芯片上,如omap3430,采用pld指令后,同一個實現可以有50%的性能提升。在較新的芯片上,如msm7230/s5pc110上,性能基本沒有區別,甚至同一個實現沒有pld指令后,性能稍稍有些提升。這也許是因為pld指令沒有效果,倒反在每個循環中浪費了時鐘周期造成的。
        40. 采用ple指令的實現的性能令人大失所望。這也說明如果沒有很好的模型設計,軟件去干預cache的使用,很容易會造成性能的惡化。
        41. Snapdragon平臺有最好的cache性能。超出cache后,各種實現(包括C語言實現)的性能基本一致,也很高效。這也許是Snapdragon平臺13-stage load/store pipeline[][]的設計造成的。這個特性對高級語言是有好處的。因為編程不可能在很多地方采用匯編語言。這樣開發人員就不必過多地考慮匯編優化,依賴編譯器就可以了。
        42. s5pc110平臺有最好的平均性能。超出cache后,NEON實現的性能最好,基本保持一條水平線。
        43. 在small/big block size下各個硬件平臺的表現

          性能因為block size分為fit in cache / out of cache兩種表現,所以做兩個剖面做對比分析。

        • 8K block size。體現fit in cache時的性能。
        • 8M block size。體現out of cache時的性能。
        1. M?ns Rullg?rd的實現

          因為M?ns Rullg?rd的實現最簡單,除了一個循環體外,沒有其它判斷代碼,可以認為是體現平臺速度極限的實現。

        2. ARM的實現

        3. NEON的實現

        4. 小結

        5. NEON指令的性能總是要高于ARM指令的性能。隨著發展ARM/NEON指令之間性能差在縮小。
        6. 交替使用ARM/NEON指令,在fit in cache條件下性能要差于NEON版本。在out of cache條件下,兩個版本性能基本一樣。
        7. 在fit in cache條件下,Snapdragon平臺有最好的性能。超過第二名s5pc110大約為43%。
        8. 在out of cache條件下,s5pc110有最好的性能。超過第二名omap3730大約為57%。
        9. 在同一個硬件平臺下,超頻(如i.MX53 800/1000MHZ & msm7x30 800/1000MHZ)對memory性能影響很小。
        10. 實用ARM/NEON實現在各個硬件平臺的表現

          通過同一種實現在不同硬件平臺上性能的對比,結合上一節的圖表,可以評價一種實現的平均性能,也就是適應性。

        11. ARM的實現

        12. NEON的實現

        13. 小結

        14. 同一種的實現,在不同的硬件平臺上都有不同的表現。沒有一種實現在所有平臺上是最好的。
        15. Codesourcery版本,包括ARM/NEON版本,有很好的適應性。不愧是做toolchain的公司。
        16. Siarhei Siamashka的NEON版本也有很好的適應性。NOKIA的技術實力也很強。這哥們好像也是pixman項目里面做NEON優化的主力。
        17. Qualcomm版本只適合Snapdragon平臺。期待以后能在msm8660以及后續的芯片上進行測試。
        18. 總結

        19. 在block size = 512B ~ 32K之間,有一個性能高臺,block size = 256K也有一個性能的轉折。這個特性體現了32KB L1 / 256KB L2 cache的影響。
        20. NEON指令的性能總是要高于ARM指令的性能。隨著發展ARM/NEON指令之間性能差在縮小。交替使用ARM/NEON指令,性能往往要差于NEON版本。
        21. 如果沒有很好的模型設計,軟件去干預cache的使用,很容易會造成性能的惡化。
        22. 在fit in cache條件下,Snapdragon平臺有最好的性能。
        23. 在out of cache條件下,s5pc110有最好的性能。
        24. 在同一個硬件平臺下,超頻對memory性能影響很小。
        25. 同一種的實現,在不同的硬件平臺上都有不同的表現。沒有一種實現在所有平臺上是最好的。
        26. 進一步的測試

          因為在Cortex-A8系列芯片里,NEON模塊是必有的。而在Cortex-A9系列芯片里,NEON模塊是可選的。因為NEON模塊會影響到die size,因而影響功耗和成本。因此有些Cortex-A9芯片,如Nvidia Tegra250,沒帶有NEON模塊。那么有無NEON模塊會對軟件性能造成什么樣的影響呢?



        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 互助| 平潭县| 太和县| 穆棱市| 桂林市| 女性| 景宁| 宿州市| 南宁市| 常州市| 富民县| 宁强县| 饶阳县| 凤城市| 信丰县| 余江县| 龙泉市| 连城县| 伊春市| 吉水县| 堆龙德庆县| 高平市| 乐清市| 浑源县| 巧家县| 六枝特区| 新蔡县| 洞头县| 宜川县| 金秀| 临邑县| 秦皇岛市| 客服| 邢台市| 沈丘县| 白水县| 灵寿县| 灵璧县| 攀枝花市| 太白县| 旅游|