Examples of NEON in Android and neonandroid
1. Open Eclipse, File --> New --> AndroidApplication Project --> Application Name: Hello-Neon, Project Name: Hello-Neon, Package Name: com. hello_neon.android, Minimum Required SDK: API 9: Android 2.3 (Gingerbread), Next --> remove the check box for Create custom launcher icon, Next --> ActivityName: Hello_NeonProjectActivity, Finish.
2. Open src --> com. hello_neon.android --> Hello_NeonProjectActivity.java under the Hello-Neon project and change its content:
package com.hello_neon.android;import android.os.Bundle;import android.app.Activity;import android.widget.TextView;public class Hello_NeonProjectActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* Create a TextView and set its content. * the text is retrieved by calling a native function. */ TextView tv = new TextView(this); tv.setText( stringFromJNI() ); setContentView(tv); } /* A native method that is implemented by the * 'helloneon' native library, which is packaged with this application. */ public native String stringFromJNI(); /* this is used to load the 'helloneon' library on application * startup. The library has already been unpacked into * /data/data/com.example.neon/lib/libhelloneon.so at * installation time by the package manager. */ static { System.loadLibrary("helloneon"); }}
3. Save the Hello_NeonProjectActivity.java file, open the command line window, locate it in the \ bin \ classes directory, and enter the command javah-classpath D: \ ProgramFiles \ Android \ android-sdk \ platforms \ android-9 \ android. jar; com. hello_neon.android.Hello_NeonProjectActivity will generate the com_hello_neon_android_Hello_NeonProjectActivity.h file under the \ bin \ classes directory (Description :*. jar can also be another version );
4. Select the Hello-Neon project and right-click --> New --> Folder to create a jni Folder. in this Folder, add Android. mk, Application. mk, helloneon. c, helloneon-intrinsics.c, helloneon-intrinsics.h five files, the content is:
Android. mk:
LOCAL_PATH: = $ (call my-dir) include $ (CLEAR_VARS) LOCAL_MODULE: = helloneon # Fill in the source file path LOCAL_SRC_FILES: = helloneon. c helloneon-intrinsics.c # default include header file path LOCAL_C_INCLUDES: =\$ (LOCAL_PATH) \ $ (LOCAL_PATH )/.. # A series of projects after-g are added to use the arm_neon-h header file,-mfloat-abi = softfp-mfpu = neon using arm_neon.h must be LOCAL_CFLAGS: =-g-mfloat-abi = softfp-mfpu = neon-march = armv7-a-mtune = cortex-a8LOCAL_LDLIBS: =-lz-llogTARGET_ARCH_ABI: = armeabi-v7a LOCAL_ARM_MODE: = armifeq ($ (TARGET_ARCH_ABI ), armeabi-v7a) # Use NEON optimization technology LOCAL_ARM_NEON: = true # LOCAL_CFLAGS: =-DHAVE_NEON = nodes: = cpufeatures # generate dynamic call Library include $ (BUILD_SHARED_LIBRARY) $ (call import-module, cpufeatures)
Application. mk:
APP_PROJECT_PATH: = $ (call my-dir )/.. APP_PLATFORM: = android-10 # choose which library to compile against in your MakefileAPP_STL: = stlport_static # APP_ABI specifies the type of the compiled target platform and can be optimized for different platforms, x86 or armeabi-v7a # Build both ARMv5TE and ARMv7-A machine code. APP_ABI: = armeabi armeabi-v7aAPP_CPPFLAGS + =-fexceptions # for using c ++ features, you need to enable these in your MakefileAPP_CPP_FEATURES + = exceptions rtti
Helloneon. c:
#include <jni.h>#include <time.h>#include <stdio.h>#include <stdlib.h>#include <cpu-features.h>#include "helloneon-intrinsics.h"#define DEBUG 0#define HAVE_NEON#if DEBUG#include <android/log.h># define D(x...) __android_log_print(ANDROID_LOG_INFO,"helloneon",x)#else# define D(...) do {} while (0)#endif/* return current time in milliseconds */static doublenow_ms(void){ struct timespec res; clock_gettime(CLOCK_REALTIME, &res); return 1000.0*res.tv_sec + (double)res.tv_nsec/1e6;}/* this is a FIR filter implemented in C */static voidfir_filter_c(short *output, const short* input, const short* kernel, int width, int kernelSize){ int offset = -kernelSize/2; int nn; for (nn = 0; nn < width; nn++) { int sum = 0; int mm; for (mm = 0; mm < kernelSize; mm++) { sum += kernel[mm]*input[nn+offset+mm]; } output[nn] = (short)((sum + 0x8000) >> 16); }}#define FIR_KERNEL_SIZE 32#define FIR_OUTPUT_SIZE 2560#define FIR_INPUT_SIZE (FIR_OUTPUT_SIZE + FIR_KERNEL_SIZE)#define FIR_ITERATIONS 600static const short fir_kernel[FIR_KERNEL_SIZE] = { 0x10, 0x20, 0x40, 0x70, 0x8c, 0xa2, 0xce, 0xf0, 0xe9, 0xce, 0xa2, 0x8c, 070, 0x40, 0x20, 0x10, 0x10, 0x20, 0x40, 0x70, 0x8c, 0xa2, 0xce, 0xf0, 0xe9, 0xce, 0xa2, 0x8c, 070, 0x40, 0x20, 0x10 };static short fir_output[FIR_OUTPUT_SIZE];static short fir_input_0[FIR_INPUT_SIZE];static const short* fir_input = fir_input_0 + (FIR_KERNEL_SIZE/2);static short fir_output_expected[FIR_OUTPUT_SIZE];/* This is a trivial JNI example where we use a native method * to return a new VM String. See the corresponding Java source * file located at: * * apps/samples/hello-neon/project/src/com/example/neon/HelloNeon.java */JNIEXPORT jstring JNICALL Java_com_hello_1neon_android_Hello_1NeonProjectActivity_stringFromJNI(JNIEnv *env, jobject thiz){ char* str; uint64_t features; char buffer[512]; char tryNeon = 0; double t0, t1, time_c, time_neon; /* setup FIR input - whatever */ { int nn; for (nn = 0; nn < FIR_INPUT_SIZE; nn++) { fir_input_0[nn] = (5*nn) & 255; } fir_filter_c(fir_output_expected, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE); } /* Benchmark small FIR filter loop - C version */ t0 = now_ms(); { int count = FIR_ITERATIONS; for (; count > 0; count--) { fir_filter_c(fir_output, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE); } } t1 = now_ms(); time_c = t1 - t0; asprintf(&str, "FIR Filter benchmark:\nC version : %g ms\n", time_c); strlcpy(buffer, str, sizeof buffer); free(str); strlcat(buffer, "Neon version : ", sizeof buffer); if (android_getCpuFamily() != ANDROID_CPU_FAMILY_ARM) { strlcat(buffer, "Not an ARM CPU !\n", sizeof buffer); goto EXIT; } features = android_getCpuFeatures(); if ((features & ANDROID_CPU_ARM_FEATURE_ARMv7) == 0) { strlcat(buffer, "Not an ARMv7 CPU !\n", sizeof buffer); goto EXIT; } /* HAVE_NEON is defined in Android.mk ! */#ifdef HAVE_NEON if ((features & ANDROID_CPU_ARM_FEATURE_NEON) == 0) { strlcat(buffer, "CPU doesn't support NEON !\n", sizeof buffer); goto EXIT; } /* Benchmark small FIR filter loop - Neon version */ t0 = now_ms(); { int count = FIR_ITERATIONS; for (; count > 0; count--) { fir_filter_neon_intrinsics(fir_output, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE); } } t1 = now_ms(); time_neon = t1 - t0; asprintf(&str, "%g ms (x%g faster)\n", time_neon, time_c / (time_neon < 1e-6 ? 1. : time_neon)); strlcat(buffer, str, sizeof buffer); free(str); /* check the result, just in case */ { int nn, fails = 0; for (nn = 0; nn < FIR_OUTPUT_SIZE; nn++) { if (fir_output[nn] != fir_output_expected[nn]) { if (++fails < 16) D("neon[%d] = %d expected %d", nn, fir_output[nn], fir_output_expected[nn]); } } D("%d fails\n", fails); }#else /* !HAVE_NEON */ strlcat(buffer, "Program not compiled with ARMv7 support !\n", sizeof buffer);#endif /* !HAVE_NEON */EXIT: return (*env)->NewStringUTF(env, buffer);}
Helloneon-intrinsics.h:
#ifndef HELLONEON_INTRINSICS_H#define HELLONEON_INTRINSICS_Hvoid fir_filter_neon_intrinsics(short *output, const short* input, const short* kernel, int width, int kernelSize);#endif /* HELLONEON_INTRINSICS_H */
Helloneon-intrinsics.c:
#include "helloneon-intrinsics.h"#include <arm_neon.h>/* this source file should only be compiled by Android.mk when targeting * the armeabi-v7a ABI, and should be built in NEON mode */voidfir_filter_neon_intrinsics(short *output, const short* input, const short* kernel, int width, int kernelSize){#if 1 int nn, offset = -kernelSize/2; for (nn = 0; nn < width; nn++) { int mm, sum = 0; int32x4_t sum_vec = vdupq_n_s32(0); for(mm = 0; mm < kernelSize/4; mm++) { int16x4_t kernel_vec = vld1_s16(kernel + mm*4); int16x4_t input_vec = vld1_s16(input + (nn+offset+mm*4)); sum_vec = vmlal_s16(sum_vec, kernel_vec, input_vec); } sum += vgetq_lane_s32(sum_vec, 0); sum += vgetq_lane_s32(sum_vec, 1); sum += vgetq_lane_s32(sum_vec, 2); sum += vgetq_lane_s32(sum_vec, 3); if(kernelSize & 3) { for(mm = kernelSize - (kernelSize & 3); mm < kernelSize; mm++) sum += kernel[mm] * input[nn+offset+mm]; } output[nn] = (short)((sum + 0x8000) >> 16); }#else /* for comparison purposes only */ int nn, offset = -kernelSize/2; for (nn = 0; nn < width; nn++) { int sum = 0; int mm; for (mm = 0; mm < kernelSize; mm++) { sum += kernel[mm]*input[nn+offset+mm]; } output[nn] = (short)((sum + 0x8000) >> 16); }#endif}
5. Use NDK to generate. so file: select project --> Properties --> Builders --> New --> Select Program --> OK, Name: Hello_Neon_Builder, Location: D: \ ProgramFiles \ Android \ android-sdk \ android-ndk-r9 \ ndk-build.cmd, Working Directory: E: \ NEON \ Eclipse \ Hello-Neon --> Apply, select Refresh, check Refreshresources upon completion, select Specific resources and click Specify Resources ..., Check the libs folder under the Hello-Neon project, Finish --> Apply, BuildOptions, and Allocate Console (necessary for input), After a "Clean", During manualbuilds, During auto builds, specify working set of relevant resources, click SpecifyResoures ..., Check the jni folder under the Hello-Neon project and Finish --> Apply --> OK. The libhelloneon. so file is generated in the libs folder;
6. Select Hello-Neon, --> Run As --> AndroidApplication. The running result is:
FIRFilter benchmark:
C version: 282.84 MS
Neon version: 135985 MS (x2.07994 faster)
The above is the operation procedure of the. c file. If the. c file is a. cpp file, you need to change the two files:
1. Change Android. mk:
LOCAL_PATH: = $ (call my-dir) include $ (CLEAR_VARS) LOCAL_MODULE: = helloneon # Fill in the source file path LOCAL_SRC_FILES: = helloneon. cpp helloneon-intrinsics.cpp # default include header file path LOCAL_C_INCLUDES: =\$ (LOCAL_PATH) \ $ (LOCAL_PATH )/.. # A series of projects after-g are added to use the arm_neon-h header file,-mfloat-abi = softfp-mfpu = neon using arm_neon.h must be LOCAL_CFLAGS: =-g-mfloat-abi = softfp-mfpu = neon-march = armv7-a-mtune = cortex-a8LOCAL_LDLIBS: =-lz-llogTARGET_ARCH_ABI: = armeabi-v7a LOCAL_ARM_MODE: = armifeq ($ (TARGET_ARCH_ABI ), armeabi-v7a) # Use NEON optimization technology LOCAL_ARM_NEON: = true # LOCAL_CFLAGS: =-DHAVE_NEON = nodes: = cpufeatures # generate dynamic call Library include $ (BUILD_SHARED_LIBRARY) $ (call import-module, cpufeatures)
2. Change helloneon. c:
#include <jni.h>#include <time.h>#include <stdio.h>#include <stdlib.h>#include <cpu-features.h>#include "helloneon-intrinsics.h"#define DEBUG 0#define HAVE_NEON#ifdef __cplusplusextern "C" {#endif#if DEBUG#include <android/log.h># define D(x...) __android_log_print(ANDROID_LOG_INFO,"helloneon",x)#else# define D(...) do {} while (0)#endif/* return current time in milliseconds */static doublenow_ms(void){ struct timespec res; clock_gettime(CLOCK_REALTIME, &res); return 1000.0*res.tv_sec + (double)res.tv_nsec/1e6;}/* this is a FIR filter implemented in C */static voidfir_filter_c(short *output, const short* input, const short* kernel, int width, int kernelSize){ int offset = -kernelSize/2; int nn; for (nn = 0; nn < width; nn++) { int sum = 0; int mm; for (mm = 0; mm < kernelSize; mm++) { sum += kernel[mm]*input[nn+offset+mm]; } output[nn] = (short)((sum + 0x8000) >> 16); }}#define FIR_KERNEL_SIZE 32#define FIR_OUTPUT_SIZE 2560#define FIR_INPUT_SIZE (FIR_OUTPUT_SIZE + FIR_KERNEL_SIZE)#define FIR_ITERATIONS 600static const short fir_kernel[FIR_KERNEL_SIZE] = { 0x10, 0x20, 0x40, 0x70, 0x8c, 0xa2, 0xce, 0xf0, 0xe9, 0xce, 0xa2, 0x8c, 070, 0x40, 0x20, 0x10, 0x10, 0x20, 0x40, 0x70, 0x8c, 0xa2, 0xce, 0xf0, 0xe9, 0xce, 0xa2, 0x8c, 070, 0x40, 0x20, 0x10 };static short fir_output[FIR_OUTPUT_SIZE];static short fir_input_0[FIR_INPUT_SIZE];static const short* fir_input = fir_input_0 + (FIR_KERNEL_SIZE/2);static short fir_output_expected[FIR_OUTPUT_SIZE];/* This is a trivial JNI example where we use a native method * to return a new VM String. See the corresponding Java source * file located at: * * apps/samples/hello-neon/project/src/com/example/neon/HelloNeon.java */JNIEXPORT jstring JNICALL Java_com_hello_1neon_android_Hello_1NeonProjectActivity_stringFromJNI(JNIEnv *env, jobject thiz){ char str[512] = {0}; uint64_t features; char buffer[512]; char tryNeon = 0; double t0, t1, time_c, time_neon; /* setup FIR input - whatever */ { int nn; for (nn = 0; nn < FIR_INPUT_SIZE; nn++) { fir_input_0[nn] = (5*nn) & 255; } fir_filter_c(fir_output_expected, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE); } /* Benchmark small FIR filter loop - C version */ t0 = now_ms(); { int count = FIR_ITERATIONS; for (; count > 0; count--) { fir_filter_c(fir_output, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE); } } t1 = now_ms(); time_c = t1 - t0; sprintf(str, "FIR Filter benchmark:\nC version : %g ms\n", time_c); strlcpy(buffer, str, sizeof buffer); strlcat(buffer, "Neon version : ", sizeof buffer); if (android_getCpuFamily() != ANDROID_CPU_FAMILY_ARM) { strlcat(buffer, "Not an ARM CPU !\n", sizeof buffer); goto EXIT; } features = android_getCpuFeatures(); if ((features & ANDROID_CPU_ARM_FEATURE_ARMv7) == 0) { strlcat(buffer, "Not an ARMv7 CPU !\n", sizeof buffer); goto EXIT; } /* HAVE_NEON is defined in Android.mk ! */#ifdef HAVE_NEON if ((features & ANDROID_CPU_ARM_FEATURE_NEON) == 0) { strlcat(buffer, "CPU doesn't support NEON !\n", sizeof buffer); goto EXIT; } /* Benchmark small FIR filter loop - Neon version */ t0 = now_ms(); { int count = FIR_ITERATIONS; for (; count > 0; count--) { fir_filter_neon_intrinsics(fir_output, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE); } } t1 = now_ms(); time_neon = t1 - t0; sprintf(str, "%g ms (x%g faster)\n", time_neon, time_c / (time_neon < 1e-6 ? 1. : time_neon)); strlcat(buffer, str, sizeof buffer); /* check the result, just in case */ { int nn, fails = 0; for (nn = 0; nn < FIR_OUTPUT_SIZE; nn++) { if (fir_output[nn] != fir_output_expected[nn]) { if (++fails < 16) D("neon[%d] = %d expected %d", nn, fir_output[nn], fir_output_expected[nn]); } } D("%d fails\n", fails); }#else /* !HAVE_NEON */ strlcat(buffer, "Program not compiled with ARMv7 support !\n", sizeof buffer);#endif /* !HAVE_NEON */EXIT: return env->NewStringUTF(buffer);}#ifdef __cplusplus}#endif
References:
1. http://blog.csdn.net/fengbingchun/article/details/11580983
2. hello-neon example code in android-ndk-r9-windows-x86_64
How to Use Handler in Android
You can directly create your own thread to complete some work.
Handler is mainly used to interact with the main UI thread. For example:
1. You use handler to send a message, and then receive and process the message in the handler thread to avoid affecting other processing tasks of the UI main thread by directly processing transactions in the UI main thread.
2. You can pass the handler object to other processes to send events to you through handler in other processes.
3. You can use handler to send messages in a delayed manner to process some transactions.
Hello, why is the setTitle (Rstringmain_title) statement used in the resource reference in android incorrect?
This kind of error is easy to find. You can check whether there is any resource main_title under String or whether the resource is added to your software. If yes, you can find the id in the R. java file.