Android 转换为C/NDK/JNI的代码的效率低于Java原始版本
这是我第一次深入NDK 为了提高性能,我想重写NDK。我的Android 转换为C/NDK/JNI的代码的效率低于Java原始版本,android,c,performance,android-ndk,java-native-interface,Android,C,Performance,Android Ndk,Java Native Interface,这是我第一次深入NDK 为了提高性能,我想重写NDK。我的c文件如下所示: #include <jni.h> #include <stdbool.h> #include <stdio.h> #include <time.h> #include <android/log.h> JNIEXPORT jbyteArray JNICALL Java_com_company_app_tools_NV21FrameRotator_rotateNV
c
文件如下所示:
#include <jni.h>
#include <stdbool.h>
#include <stdio.h>
#include <time.h>
#include <android/log.h>
JNIEXPORT jbyteArray JNICALL
Java_com_company_app_tools_NV21FrameRotator_rotateNV21(JNIEnv *env, jclass thiz,
jbyteArray data, jbyteArray output,
jint width, jint height, jint rotation) {
clock_t start, end;
double cpu_time_used;
start = clock();
jbyte *dataPtr = (*env)->GetByteArrayElements(env, data, NULL);
jbyte *outputPtr = (*env)->GetByteArrayElements(env, output, NULL);
unsigned int frameSize = width * height;
bool swap = rotation % 180 != 0;
bool xflip = rotation % 270 != 0;
bool yflip = rotation >= 180;
for (unsigned int j = 0; j < height; j++) {
for (unsigned int i = 0; i < width; i++) {
unsigned int yIn = j * width + i;
unsigned int uIn = frameSize + (j >> 1u) * width + (i & ~1u);
unsigned int vIn = uIn + 1;
unsigned int wOut = swap ? height : width;
unsigned int hOut = swap ? width : height;
unsigned int iSwapped = swap ? j : i;
unsigned int jSwapped = swap ? i : j;
unsigned int iOut = xflip ? wOut - iSwapped - 1 : iSwapped;
unsigned int jOut = yflip ? hOut - jSwapped - 1 : jSwapped;
unsigned int yOut = jOut * wOut + iOut;
unsigned int uOut = frameSize + (jOut >> 1u) * wOut + (iOut & ~1u);
unsigned int vOut = uOut + 1;
outputPtr[yOut] = (jbyte) (0xff & dataPtr[yIn]);
outputPtr[uOut] = (jbyte) (0xff & dataPtr[uIn]);
outputPtr[vOut] = (jbyte) (0xff & dataPtr[vIn]);
}
}
(*env)->ReleaseByteArrayElements(env, data, dataPtr, 0);
(*env)->ReleaseByteArrayElements(env, output, outputPtr, 0);
end = clock();
cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
char str[10];
sprintf(str, "%f", cpu_time_used * 1000);
__android_log_write(ANDROID_LOG_ERROR, "NV21FrameRotator", str);
return output;
}
PS.Java日志有时显示的持续时间比c
文件中的本机clock()
测量的持续时间短。。。示例日志:
NV21FrameRotator: 7.942000
NV21RotatorJava: Last frame processing duration: 7403µs
NV21FrameRotator: 7.229000
NV21RotatorJava: Last frame processing duration: 7166µs
NV21FrameRotator: 16.918000
NV21RotatorJava: Last frame processing duration: 20644µs
NV21FrameRotator: 19.594000
NV21RotatorJava: Last frame processing duration: 20479µs
NV21FrameRotator: 9.484000
NV21RotatorJava: Last frame processing duration: 7274µs
编辑:compile\u commands.json
forarmeabi-v7a
(旧设备,我只构建这个)
cmakfile
:
cmake_minimum_required(VERSION 3.4.1)
add_library(NV21FrameRotator SHARED
NV21FrameRotator.c)
find_library(log-lib
log )
target_link_libraries(NV21FrameRotator
${log-lib} )
JNI的开销非常高,尤其是在传递非POD类型或缓冲区时。因此,通常调用JNI函数可能比java版本慢得多
考虑传递java.nio.ByteBuffer,以避免字节数组的潜在副本。JNI的开销非常大,尤其是在传递非POD类型或缓冲区时。因此,通常调用JNI函数可能比java版本慢得多 考虑传递java.nio.ByteBuffer,以避免字节数组的潜在副本
-Oz
构建。要更喜欢速度而不是大小,您可以添加到您的构建中。gradle:
android {
buildTypes {
release {
externalNativeBuild.cmake.cFlags "-O3"
}
}
}
#包括
#包括
#包括
#包括
#包括
JNIEXPORT jbyteArray JNICALL
Java公司应用程序工具NV21FrameRotator旋转器(JNIEnv*env,jclass thiz,
jbyteArray数据,jbyteArray输出,
jint宽度、jint高度、jint旋转){
时钟开始、结束;
使用双cpu时间;
开始=时钟();
jbyte*dataPtr=(*env)->GetByteArrayElements(env,data,NULL);
jbyte*outputPtr=(*env)->GetByteArrayElements(env,output,NULL);
无符号整数帧大小=宽度*高度;
布尔交换=旋转%180!=0;
bool xflip=旋转%270!=0;
bool yflip=旋转>=180;
无符号整数wOut=swap?高度:宽度;
无符号整数=交换?宽度:高度;
无符号整数yIn=0;
for(无符号整数j=0;jReleaseByteArrayElements(环境、数据、数据PTR、JNI_中止);
(*env)->ReleaseByteArrayElements(env,output,outputPtr,0);
结束=时钟();
使用的cpu时间=((双精度)(结束-开始))/每秒时钟数;
__安卓系统日志打印(安卓系统日志错误,“NV21FrameRotator”、“%.1f ms”、cpu使用时间*1000);
返回输出;
}
-Oz
构建。要更喜欢速度而不是大小,您可以添加到您的构建中。gradle:
android {
buildTypes {
release {
externalNativeBuild.cmake.cFlags "-O3"
}
}
}
#包括
#包括
#包括
#包括
#包括
JNIEXPORT jbyteArray JNICALL
Java公司应用程序工具NV21FrameRotator旋转器(JNIEnv*env,jclass thiz,
jbyteArray数据,jbyteArray输出,
jint宽度、jint高度、jint旋转){
时钟开始、结束;
使用双cpu时间;
开始=时钟();
jbyte*dataPtr=(*env)->GetByteArrayElements(env,data,NULL);
jbyte*outputPtr=(*env)->GetByteArrayElements(env,output,NULL);
无符号整数帧大小=宽度*高度;
布尔交换=旋转%180!=0;
bool xflip=旋转%270!=0;
android {
buildTypes {
release {
externalNativeBuild.cmake.cFlags "-O3"
}
}
}