在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试

本文介绍了基于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-bit128-bit不等)和cache的预取preloadpreload 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)指令对性能的影响,以及在芯片优化和工艺进步后,这些影响的变化趋势。同时希望芯片设计人员在了解软件实现的基础上,给予一个知其然,也知其所以然的解释,进而指导进一步提高性能的方向。

  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 / NEONpipeline有可能异步处理,交替使用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~3pld指令填充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。这是QualCommCode 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

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第1张图片

  25. imx53 1000MHZ

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第2张图片

  26. imx53 800MHZ

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第3张图片

  27. msm7230 1000MHZ

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第4张图片

  28. msm7230 800MHZ

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第5张图片

  29. msm8250 1000MHZ

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第6张图片

  30. omap3430 550MHZ

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第7张图片

  31. omap3730 1000MHZ

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第8张图片

  32. s5pc100 665MHZ

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第9张图片

  33. s5pc110 1000MHZ

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第10张图片

    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的实现最简单,除了一个循环体外,没有其它判断代码,可以认为是体现平台速度极限的实现。

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第11张图片

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第12张图片

  2. ARM的实现

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第13张图片

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第14张图片

  3. NEON的实现

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第15张图片

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第16张图片

  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的实现

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第17张图片

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第18张图片

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第19张图片

  12. NEON的实现

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第20张图片

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第21张图片

     

    在Cortex-A8平台下memcpy ARM/NEON汇编性能的测试_第22张图片

  13. 小结

  14. 同一种的实现,在不同的硬件平台上都有不同的表现。没有一种实现在所有平台上是最好的。
  15. Codesourcery版本,包括ARM/NEON版本,有很好的适应性。不愧是做toolchain的公司。
  16. Siarhei SiamashkaNEON版本也有很好的适应性。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模块会对软件性能造成什么样的影响呢?

  27. 参考文档

  28. ARM Cortex-A8

    http://en.wikipedia.org/wiki/ARM_Cortex-A8

     

  29. Cortex?-A8 Technical Reference Manual

    http://infocenter.arm.com/help/topic/com.arm.doc.ddi0344k/index.html

     

  30. c0, Cache Size Identification Registers

    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344f/Chdebced.html

     

  31. What is the fastest way to copy memory on a Cortex-A8?

    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka13544.html

     

  32. ARM-NEON memory hazards

    http://hardwarebug.org/2008/12/31/arm-neon-memory-hazards/

     

  33. i.MX5 family

    http://en.wikipedia.org/wiki/I.MX

     

  34. Freescale i.MX515

    http://www.7-cpu.com/cpu/imx515.html

     

  35. Snapdragon (System on Chip)

    http://en.wikipedia.org/wiki/Snapdragon_(System_on_Chip)

     

  36. Qualcomm Reveals Details on Scorpion Core

    http://www.bdti.com/InsideDSP/2007/11/14/Qualcomm

     

  37. Qualcomm Snapdragon

    http://www.7-cpu.com/cpu/Snapdragon.html

     

  38. ODROID

    http://hardkernel.com/

     

  39. OMAP3 family

    http://en.wikipedia.org/wiki/OMAP3

     

  40. Omap World

    http://omapworld.com/

     

  41. beagleboard

    http://beagleboard.org/

     

  42. Siarhei Siamashka: Optimized Memory Copying Functions For Nokia 770

    http://lists.maemo.org/pipermail//maemo-developers/2006-March/003269.html

     

  43. Nicolas Pitre: ARM memcpy and memmove

    http://sourceware.org/ml/libc-ports/2006-10/msg00024.html

     

  44. CodeSourcery C Library

    http://www.codesourcery.com/

     

  45. Neon memcpy: Attempts to do a memcpy with Neon registers if possible

    https://www.codeaurora.org/patches/quic/qsd/SAMPLE_3918_NEON_MEMOPS_20101001.tar.gz

     

  46. M?ns Rullg?rd: memory bandwidth problem - Beagle Board

    http://groups.google.com/group/beagleboard/browse_thread/thread/12c7bd415fbc0993/c54dde7b9d55cf99

     

  47. Siarhei Siamashka: ARM: NEON optimized implementation of memcpy

    http://sourceware.org/ml/libc-ports/2009-07/msg00003.html

     

  48. Memory tester

    http://sandbox.movial.com/gitweb?p=mmem.git;a=summary

  49. http://houh-1984.blog.163.com 

    转载自Shuyong Chen http://tektalk.org/wp-content/uploads/2011/03/memspeed.odt

    本文介绍了基于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-bit128-bit不等)和cache的预取preloadpreload 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. 同一种的实现,在不同的硬件平台上都有不同的表现。没有一种实现在所有平台上是最好的。

你可能感兴趣的:(汇编,cache,测试,语言,Nokia,平台)