当时是需要对一个终端耗时任务做矩阵加速,我选了OpenBlas开源方案,事实证明在ARM平台上能用的开源的方案中,OpenBlas做的算相当可以的了。以后有时间还想自己实现一下矩阵乘法的加速。做优化这个过程还是很吸引人的。
编译准备
原理还是一样,首先在本地配置安卓的交叉编译环境,编译出OpenBlas的静态库,用于JNI链接。github上有详细的教程,包括我后来的一个编译错误也是在上面找到了解决方案。详见 How to build OpenBLAS for Android
注意教程上建议在做交叉编译之前先构建一个标准工具链,其实就是交叉编译的环境,第一次我图省事只配置了arm-linux-androideabi-gcc
的环境变量,make
的时候就会出现找不到头文件的错误。
NDK已经提供了一个脚本做这件事情,在路径/Users/wujian/Library/Android/sdk/ndk-bundle/build/tools
下有一个make_standalone_toolchain.py
脚本,通过执行命令1
make_standalone_toolchain.py --arch arm --api 21 --install-dir /dst/path/
之后我们对这个文件夹配置环境变量即可。
编译
不需要Fortran,针对ARMv71
make TARGET=ARMV7 HOSTCC=gcc CC=arm-linux-androideabi-gcc NOFORTRAN=1 > make.log
编译时间不长,几分钟吧,编译完会提示安装,执行1
make PREFIX=/dst/path install
最终安装目录下存在头文件和静态库,这个就是我们最终需要的。
AS中使用JNI链接
这里有个很恶心的问题,目前我没有找到gradle中如何配置链接静态库的方法,只能借助Android.mk文件,但是由于AS默认是执行gradle的编译过程,所以需要在build.gradle中禁用JNI(否则他还是那么一套规程),之后手动配置build的过程。
禁用AS默认的JNI目录:1
2
3sourceSets.main {
jni.srcDirs = []
}
配置编译规则1
2
3
4
5
6
7
8
9
10
11task ndkBuild(type: org.gradle.api.tasks.Exec, description: "compile JNI by NDK") {
commandLine "/Users/wujian/Library/Android/sdk/ndk-bundle/ndk-build",
'NDK_PROJECT_PATH=build/intermediates/ndk',
'NDK_LIBS_OUT=src/main/jniLibs',
'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
'NDK_APPLICATION_MK=src/main/jni/Application.mk'
}
tasks.withType(JavaCompile) {
compileTask->compileTask.dependsOn ndkBuild
}
同时在JNI目录下加入Android.mk和Application.mk文件,如下,具体含义之后再解释,这里先说明配置过程。Android.mk中详细说明了OpenBlas静态库的连接过程。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := blas
LOCAL_SRC_FILES := libopenblas_armv7p-r0.2.20.dev.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := math
LOCAL_SRC_FILES := impl.cpp
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS += -mhard-float -D_NDK_MATH_NO_SOFTFP=1
LOCAL_LDFLAGS += -Wl,--no-warn-mismatch -lm_hard
LOCAL_STATIC_LIBRARIES := blas
endif
LOCAL_CFLAGS += -DUSE_JNI
LOCAL_CFLAGS += -DPFFFT_SIMD_DISABLE
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)1
2APP_ABI := armeabi-v7a
APP_PLATFORM := android-19
再把OpenBlas的头文件加入JNI目录下,include使用即可,接下来就可以make了。
后续问题
我两次做静态链接时都出现了如下问题,第一次是使用NENO库:
后来在网上查了许久,是编译选项和ABI的问题,这在How to build OpenBLAS for Android最后一部分也说明了。我采取的是第二种方案,因为这里是使用Android.mk来配置编译规则的。