注册 登录
自由的生活_软路由 返回首页

心想事成的个人空间 https://bbs.routerclub.com/?681 [收藏] [复制] [分享] [RSS]

日志

Android NDK(ARM开发)使用NEON优化

已有 3110 次阅读2014-2-21 19:28 | Android, 开发

在进行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两个文件:

Android.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,需要指定编译的目标平台类型:

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优化的代码

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进行优化的代码

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、汇编优化

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
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 }

最后的结果对比:

  1. C-version:             15.1 cycles per pixel.    
  2. NEON-version:       9.9 cycles per pixel.    
  3. Assembler:             2.0 cycles per pixel. 

路过

雷人

握手

鲜花

鸡蛋

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

QQ|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.

返回顶部