|
在进行Android开发时,一般考虑加速某些算法处理速率时,需要使用NDK进行开发,
为了进一步加速程序执行速率,还可以进行汇编级别的优化。
比如采用 NEON 技术进行代码的优化,以实现模块处理效率的成倍增长。
在C/C++中使用内联汇编的用法如下:
1 2 3 4 | asm( "ADD R0,R0,#1 \n\t" // 使R0寄存器值增加1,后面加换行符和制表符是为了汇编代码的美观,其中有多条指令时 换行符是必须的 "SUB R0,R0,#1 " // 使R0寄存器的值减少1 ); |
然后是如何在NDK中编译使用这种指令,需要修改Android.mk和Application.mk两个文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | LOCAL_PATH := $(call my- dir ) include $(CLEAR_VARS) # 这里填写要编译的源文件路径,这里只列举了一部分 LOCAL_SRC_FILES := NcHevcDecoder.cpp JNI_OnLoad.cpp TAppDecTop.cpp # 默认包含的头文件路径 LOCAL_C_INCLUDES := \ $(LOCAL_PATH) \ $(LOCAL_PATH)/.. # -g 后面的一系列附加项目添加了才能使用 arm_neon.h 头文件 -mfloat-abi=softfp -mfpu=neon 使用 arm_neon.h 必须 LOCAL_CFLAGS := -D__cpusplus -g -mfloat-abi=softfp -mfpu=neon -march=armv7-a -mtune=cortex-a8 LOCAL_LDLIBS := -lz -llog TARGET_ARCH_ABI :=armeabi-v7a LOCAL_ARM_MODE := arm ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) # 采用NEON优化技术 LOCAL_ARM_NEON := true endif LOCAL_MODULE := avcodecinclude $(BUILD_STATIC_LIBRARY) include $(BUILD_SHARED_LIBRARY) |
下面是Application.mk,需要指定编译的目标平台类型:
1 2 3 4 5 | APP_PROJECT_PATH := $(call my- dir )/.. APP_PLATFORM := android-10 APP_STL := stlport_static APP_ABI := armeabi-v7a APP_CPPFLAGS += -fexceptions |
其中APP_ABI这句指定了编译的目标平台类型,可以针对不同平台进行优化。
当然这样指定了之后,就需要相应的设备支持NEON指令。
我的一个NDK应用,在使用上述配置之后,即NEON优化等,程序的性能提升了近一倍。
系统的处理延时由原来的 95ms左右降低到了 51ms。
后续可以使用NEON库进一步优化 NDK 程序代码,实现更加优化的结果。
PS:参考的文章有如下几篇,可能跟我的平台有所不同,所以我都不能完全照搬使用:
http://blog.csdn.net/wuzhong325/article/details/8277703
http://blog.csdn.net/wuzhong325/article/details/8277718
http://blog.chinaunix.net/uid-20715001-id-1234726.html
最后的是NEON优化示例:http://hilbert-space.de/?p=22
1、未使用NEON优化的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | void reference_convert (uint8_t * __restrict dest, uint8_t * __restrict src, int n) { int i; for (i=0; i<n; i++) { int r = *src++; // load red int g = *src++; // load green int b = *src++; // load blue // build weighted average: int y = (r*77)+(g*151)+(b*28); // undo the scale by 256 and write to memory: *dest++ = (y>>8); } } |
2、使用NEON进行优化的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | void neon_convert (uint8_t * __restrict dest, uint8_t * __restrict src, int n) { int i; uint8x8_t rfac = vdup_n_u8 (77); // 转换权值 R uint8x8_t gfac = vdup_n_u8 (151); // 转换权值 G uint8x8_t bfac = vdup_n_u8 (28); // 转换权值 B n/=8; for (i=0; i<n; i++) { uint16x8_t temp; uint8x8x3_t rgb = vld3_u8 (src); uint8x8_t result; temp = vmull_u8 (rgb.val[0], rfac); // vmull_u8 每个字节(8bit)对应相乘,结果为每个单位2字节(16bit) temp = vmlal_u8 (temp,rgb.val[1], gfac); // 每个比特对应相乘并加上 temp = vmlal_u8 (temp,rgb.val[2], bfac); result = vshrn_n_u16 (temp, 8); // 全部移位8位 vst1_u8 (dest, result); // 转存运算结果 src += 8*3; dest += 8; } } |
3、汇编优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // 这里针对生成的目标汇编代码进一步作了优化,优化的代码如下: convert_asm_neon: # r0: Ptr to destination data # r1: Ptr to source data # r2: Iteration count: push {r4-r5,lr} lsr r2, r2, #3 # build the three constants: mov r3, #77 mov r4, #151 mov r5, #28 vdup.8 d3, r3 vdup.8 d4, r4 vdup.8 d5, r5 . loop : # load 8 pixels: vld3.8 {d0-d2}, [r1]! # do the weight average: vmull.u8 q3, d0, d3 vmlal.u8 q3, d1, d4 vmlal.u8 q3, d2, d5 # shift and store: vshrn.u16 d6, q3, #8 vst1.8 {d6}, [r0]! subs r2, r2, #1 bne . loop pop { r4-r5, pc } |
最后的结果对比:
|Archiver|手机版|小黑屋|软路由 ( 渝ICP备15001194号-1|渝公网安备 50011602500124号 )
GMT+8, 2024-4-27 17:35 , Processed in 0.067071 second(s), 5 queries , Gzip On, Redis On.
Powered by Discuz! X3.5 Licensed
© 2001-2023 Discuz! Team.