改善 Android 中 memcpy 效能

在 Android 內部實做中,有許多細節涉及大量的 memcpy() 操作,比方說將一塊使用者定義的繪圖區域傳遞給 SurfaceFlinger 管理的過程,由於得先轉換成 texture,再對應為 Surface,之間至少需要三次 memcpy。由於 BeagleBoard (TI OMAP3) 透過 HDMI 輸出 (max: 1280x1024),居中涉及大量的繪圖操作,意味著 memcpy() 頻繁被呼叫著,對整體效能有顯著的影響,於是筆者花了一些時間分析。

Android 的 libc 實做 -- bionic -- 已包含針對 ARMv5 優化過的 memcpy(),詳情可參考 libc/arch-arm/bionic/memcpy.S,而 GNU Toolchain (glibc) 中,其實也有一份針對 ARMv5 優化過的 memcpy() 實做,也利用到 ARMv5 的 data prefetch 指令。既然我們採用 ARMv7 架構的 BeagleBoard,何不使用其引入的 NEON SIMD 加速指令集呢?以下就是在 BeagleBoard 所作的 benchmark:

數據如下:

  • glibc-armv5 : 181884276 B/s
  • bionic-armv5 : 225881095 B/s
  • armv7 : 269294302 B/s
參考的 ARM NEON 優化 memcpy() 實做如下: (arm-neon-memcpy.S from Måns Rullgård )
  1. .fpu neon
  2. .text

  3. .global memcpy_neon

  4. .func memcpy_neon
  5. memcpy_neon:
  6. push {r4-r11}
  7. mov r3, r0
  8. 1: subs r2, r2, #128
  9. pld [r1, #64]
  10. pld [r1, #256]
  11. pld [r1, #320]
  12. ldm r1!, {r4-r11}
  13. vld1.64 {d0-d3}, [r1,:128]!
  14. vld1.64 {d4-d7}, [r1,:128]!
  15. vld1.64 {d16-d19}, [r1,:128]!
  16. stm r3!, {r4-r11}
  17. vst1.64 {d0-d3}, [r3,:128]!
  18. vst1.64 {d4-d7}, [r3,:128]!
  19. vst1.64 {d16-d19}, [r3,:128]!
  20. bgt 1b
  21. pop {r4-r11}
  22. bx lr
  23. .endfunc
至於 SurfaceFlinger 的操作仍有優化的空間,稍後再討論。


About this entry


  1. fastfastball 2009年8月26日 下午5:41
    作者已經移除這則留言。

張貼留言