两种方法将Android NDK samples中hello-neon改成C++

一、第一种方法:
1.修改helloneon.c 中代码
 a.将
  char*  str;
   改为
     char str[512] = {0};
 b.将
  asprintf(&str, "FIR Filter benchmark:\nC version          : %g ms\n", time_c);
   改为
     sprintf(str, "FIR Filter benchmark:\nC version    : %g ms\n", time_c);
   同时删除 free(str);
   (b 项 有两处都要修改)
 c.将
  return (*env)->NewStringUTF(env, buffer);
 改为
  return env->NewStringUTF(buffer);
2.将helloneon.c改名为helloneon.cpp
  将helloneon-intrinsics.c改名为helloneon-intrinsics.cpp
3.将Android.mk中
 将
  LOCAL_SRC_FILES := helloneon.c
 改为
  LOCAL_SRC_FILES := helloneon.cpp

 将
  LOCAL_SRC_FILES += helloneon-intrinsics.c.neon
 改为
  LOCAL_SRC_FILES += helloneon-intrinsics.cpp.neon
4.打开 helloneon.cpp
  在#include 和 各种 #define 后面添加:
 #ifdef __cplusplus
 extern "C" {
 #endif
  在代码段最后面添加:
   #ifdef __cplusplus
 }
 #endif
  不修改这一条的话,会提示找不到stringFromJNI。

不明问题:
1.经常提示一些jni和cpu-features的函数未定义。在路径中添加jni.h和cpu-features.h
2.即便是添加了arm_neon.h,还是会提示:
Type 'int16x4_t' could not be resolved helloneon-intrinsics.cpp /HelloNeon/jni line 35
但是 重启eclipse 一般就不提示了。一旦打开了helloneon-intrinsics.cpp还是会提示。

最终 hello-neon.cpp

  1 /*
  2  * Copyright (C) 2010 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  *
 16  */
 17 #include <jni.h>
 18 #include <time.h>
 19 #include <stdio.h>
 20 #include <stdlib.h>
 21 #include <cpu-features.h>
 22 #include "helloneon-intrinsics.h"
 23 
 24 #define DEBUG 0
 25 
 26 #if DEBUG
 27 #include <android/log.h>
 28 #  define  D(x...)  __android_log_print(ANDROID_LOG_INFO,"helloneon",x)
 29 #else
 30 #  define  D(...)  do {} while (0)
 31 #endif
 32 
 33 #ifdef __cplusplus
 34 extern "C" {
 35 #endif
 36 
 37 /* return current time in milliseconds */
 38 static double
 39 now_ms(void)
 40 {
 41     struct timespec res;
 42     clock_gettime(CLOCK_REALTIME, &res);
 43     return 1000.0*res.tv_sec + (double)res.tv_nsec/1e6;
 44 }
 45 
 46 
 47 /* this is a FIR filter implemented in C */
 48 static void
 49 fir_filter_c(short *output, const short* input, const short* kernel, int width, int kernelSize)
 50 {
 51     int  offset = -kernelSize/2;
 52     int  nn;
 53     for (nn = 0; nn < width; nn++) {
 54         int sum = 0;
 55         int mm;
 56         for (mm = 0; mm < kernelSize; mm++) {
 57             sum += kernel[mm]*input[nn+offset+mm];
 58         }
 59         output[nn] = (short)((sum + 0x8000) >> 16);
 60     }
 61 }
 62 
 63 #define  FIR_KERNEL_SIZE   32
 64 #define  FIR_OUTPUT_SIZE   2560
 65 #define  FIR_INPUT_SIZE    (FIR_OUTPUT_SIZE + FIR_KERNEL_SIZE)
 66 #define  FIR_ITERATIONS    600
 67 
 68 static const short  fir_kernel[FIR_KERNEL_SIZE] = {
 69     0x10, 0x20, 0x40, 0x70, 0x8c, 0xa2, 0xce, 0xf0, 0xe9, 0xce, 0xa2, 0x8c, 070, 0x40, 0x20, 0x10,
 70     0x10, 0x20, 0x40, 0x70, 0x8c, 0xa2, 0xce, 0xf0, 0xe9, 0xce, 0xa2, 0x8c, 070, 0x40, 0x20, 0x10 };
 71 
 72 static short        fir_output[FIR_OUTPUT_SIZE];
 73 static short        fir_input_0[FIR_INPUT_SIZE];
 74 static const short* fir_input = fir_input_0 + (FIR_KERNEL_SIZE/2);
 75 static short        fir_output_expected[FIR_OUTPUT_SIZE];
 76 
 77 /* This is a trivial JNI example where we use a native method
 78  * to return a new VM String. See the corresponding Java source
 79  * file located at:
 80  *
 81  *   apps/samples/hello-neon/project/src/com/example/neon/HelloNeon.java
 82  */
 83 jstring
 84 Java_com_example_neon_HelloNeon_stringFromJNI( JNIEnv* env,
 85                                                jobject thiz )
 86 {
 87     //char*  str;
 88     char str[512] = {0};
 89     uint64_t features;
 90     char buffer[512];
 91     char tryNeon = 0;
 92     double  t0, t1, time_c, time_neon;
 93 
 94     /* setup FIR input - whatever */
 95     {
 96         int  nn;
 97         for (nn = 0; nn < FIR_INPUT_SIZE; nn++) {
 98             fir_input_0[nn] = (5*nn) & 255;
 99         }
100         fir_filter_c(fir_output_expected, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE);
101     }
102 
103     /* Benchmark small FIR filter loop - C version */
104     t0 = now_ms();
105     {
106         int  count = FIR_ITERATIONS;
107         for (; count > 0; count--) {
108             fir_filter_c(fir_output, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE);
109         }
110     }
111     t1 = now_ms();
112     time_c = t1 - t0;
113 
114     sprintf(str, "FIR Filter benchmark:\nC version    : %g ms\n", time_c);
115     //asprintf(&str, "FIR Filter benchmark:\nC version          : %g ms\n", time_c);
116     strlcpy(buffer, str, sizeof buffer);
117 
118     //free(str);
119 
120     strlcat(buffer, "Neon version   : ", sizeof buffer);
121 
122     if (android_getCpuFamily() != ANDROID_CPU_FAMILY_ARM) {
123         strlcat(buffer, "Not an ARM CPU !\n", sizeof buffer);
124         goto EXIT;
125     }
126 
127     features = android_getCpuFeatures();
128     if ((features & ANDROID_CPU_ARM_FEATURE_ARMv7) == 0) {
129         strlcat(buffer, "Not an ARMv7 CPU !\n", sizeof buffer);
130         goto EXIT;
131     }
132 
133     /* HAVE_NEON is defined in Android.mk ! */
134 #ifdef HAVE_NEON
135     if ((features & ANDROID_CPU_ARM_FEATURE_NEON) == 0) {
136         strlcat(buffer, "CPU doesn't support NEON !\n", sizeof buffer);
137         goto EXIT;
138     }
139 
140     /* Benchmark small FIR filter loop - Neon version */
141     t0 = now_ms();
142     {
143         int  count = FIR_ITERATIONS;
144         for (; count > 0; count--) {
145             fir_filter_neon_intrinsics(fir_output, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE);
146         }
147     }
148     t1 = now_ms();
149     time_neon = t1 - t0;
150     sprintf(str, "%g ms   (x%g faster)\n", time_neon, time_c / (time_neon < 1e-6 ? 1. : time_neon));
151     //asprintf(&str, "%g ms (x%g faster)\n", time_neon, time_c / (time_neon < 1e-6 ? 1. : time_neon));
152     strlcat(buffer, str, sizeof buffer);
153     //free(str);
154 
155     /* check the result, just in case */
156     {
157         int  nn, fails = 0;
158         for (nn = 0; nn < FIR_OUTPUT_SIZE; nn++) {
159             if (fir_output[nn] != fir_output_expected[nn]) {
160                 if (++fails < 16)
161                     D("neon[%d] = %d expected %d", nn, fir_output[nn], fir_output_expected[nn]);
162             }
163         }
164         D("%d fails\n", fails);
165     }
166 #else /* !HAVE_NEON */
167     strlcat(buffer, "Program not compiled with ARMv7 support !\n", sizeof buffer);
168 #endif /* !HAVE_NEON */
169 EXIT:
170     //return (*env)->NewStringUTF(env, buffer); // C Version
171     return env->NewStringUTF(buffer); // C++ Version
172 }
173 
174 #ifdef __cplusplus
175 }
176 #endif
View Code

 

二、第二种方法:
1. helloneon.cpp的修改如下

  1 /*
  2  * Copyright (C) 2010 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  *
 16  */
 17 #include <jni.h>
 18 #include <time.h>
 19 #include <stdio.h>
 20 #include <stdlib.h>
 21 #include <cpu-features.h>
 22 #include "helloneon-intrinsics.h"
 23 
 24 #define DEBUG 0
 25 
 26 #if DEBUG
 27 #include <android/log.h>
 28 #  define  D(x...)  __android_log_print(ANDROID_LOG_INFO,"helloneon",x)
 29 #else
 30 #  define  D(...)  do {} while (0)
 31 #endif
 32 
 33 #ifdef __cplusplus
 34 extern "C" {
 35 #endif
 36 
 37 #define  LOG_TAG    "helloneon"
 38 #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
 39 static JavaVM *gJVM;
 40 static const char *classPathName = "com/example/neon/HelloNeon";
 41 
 42 /* return current time in milliseconds */
 43 static double
 44 now_ms(void)
 45 {
 46     struct timespec res;
 47     clock_gettime(CLOCK_REALTIME, &res);
 48     return 1000.0*res.tv_sec + (double)res.tv_nsec/1e6;
 49 }
 50 
 51 
 52 /* this is a FIR filter implemented in C */
 53 static void
 54 fir_filter_c(short *output, const short* input, const short* kernel, int width, int kernelSize)
 55 {
 56     int  offset = -kernelSize/2;
 57     int  nn;
 58     for (nn = 0; nn < width; nn++) {
 59         int sum = 0;
 60         int mm;
 61         for (mm = 0; mm < kernelSize; mm++) {
 62             sum += kernel[mm]*input[nn+offset+mm];
 63         }
 64         output[nn] = (short)((sum + 0x8000) >> 16);
 65     }
 66 }
 67 
 68 #define  FIR_KERNEL_SIZE   32
 69 #define  FIR_OUTPUT_SIZE   2560
 70 #define  FIR_INPUT_SIZE    (FIR_OUTPUT_SIZE + FIR_KERNEL_SIZE)
 71 #define  FIR_ITERATIONS    600
 72 
 73 static const short  fir_kernel[FIR_KERNEL_SIZE] = {
 74     0x10, 0x20, 0x40, 0x70, 0x8c, 0xa2, 0xce, 0xf0, 0xe9, 0xce, 0xa2, 0x8c, 070, 0x40, 0x20, 0x10,
 75     0x10, 0x20, 0x40, 0x70, 0x8c, 0xa2, 0xce, 0xf0, 0xe9, 0xce, 0xa2, 0x8c, 070, 0x40, 0x20, 0x10 };
 76 
 77 static short        fir_output[FIR_OUTPUT_SIZE];
 78 static short        fir_input_0[FIR_INPUT_SIZE];
 79 static const short* fir_input = fir_input_0 + (FIR_KERNEL_SIZE/2);
 80 static short        fir_output_expected[FIR_OUTPUT_SIZE];
 81 
 82 /* This is a trivial JNI example where we use a native method
 83  * to return a new VM String. See the corresponding Java source
 84  * file located at:
 85  *
 86  *   apps/samples/hello-neon/project/src/com/example/neon/HelloNeon.java
 87  */
 88 static jstring stringforneon( JNIEnv* env, jobject thiz )
 89 {
 90     //char*  str;
 91     char str[512] = {0};
 92     uint64_t features;
 93     char buffer[512];
 94     char tryNeon = 0;
 95     double  t0, t1, time_c, time_neon;
 96 
 97     /* setup FIR input - whatever */
 98     {
 99         int  nn;
100         for (nn = 0; nn < FIR_INPUT_SIZE; nn++) {
101             fir_input_0[nn] = (5*nn) & 255;
102         }
103         fir_filter_c(fir_output_expected, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE);
104     }
105 
106     /* Benchmark small FIR filter loop - C version */
107     t0 = now_ms();
108     {
109         int  count = FIR_ITERATIONS;
110         for (; count > 0; count--) {
111             fir_filter_c(fir_output, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE);
112         }
113     }
114     t1 = now_ms();
115     time_c = t1 - t0;
116 
117     sprintf(str, "FIR Filter benchmark:\nC version    : %g ms\n", time_c);
118     //asprintf(&str, "FIR Filter benchmark:\nC version          : %g ms\n", time_c);
119     strlcpy(buffer, str, sizeof buffer);
120 
121     //free(str);
122 
123     strlcat(buffer, "Neon version   : ", sizeof buffer);
124 
125     if (android_getCpuFamily() != ANDROID_CPU_FAMILY_ARM) {
126         strlcat(buffer, "Not an ARM CPU !\n", sizeof buffer);
127         goto EXIT;
128     }
129 
130     features = android_getCpuFeatures();
131     if ((features & ANDROID_CPU_ARM_FEATURE_ARMv7) == 0) {
132         strlcat(buffer, "Not an ARMv7 CPU !\n", sizeof buffer);
133         goto EXIT;
134     }
135 
136     /* HAVE_NEON is defined in Android.mk ! */
137 #ifdef HAVE_NEON
138     if ((features & ANDROID_CPU_ARM_FEATURE_NEON) == 0) {
139         strlcat(buffer, "CPU doesn't support NEON !\n", sizeof buffer);
140         goto EXIT;
141     }
142 
143     /* Benchmark small FIR filter loop - Neon version */
144     t0 = now_ms();
145     {
146         int  count = FIR_ITERATIONS;
147         for (; count > 0; count--) {
148             fir_filter_neon_intrinsics(fir_output, fir_input, fir_kernel, FIR_OUTPUT_SIZE, FIR_KERNEL_SIZE);
149         }
150     }
151     t1 = now_ms();
152     time_neon = t1 - t0;
153     sprintf(str, "%g ms   (x%g faster)\n", time_neon, time_c / (time_neon < 1e-6 ? 1. : time_neon));
154     //asprintf(&str, "%g ms (x%g faster)\n", time_neon, time_c / (time_neon < 1e-6 ? 1. : time_neon));
155     strlcat(buffer, str, sizeof buffer);
156     //free(str);
157 
158     /* check the result, just in case */
159     {
160         int  nn, fails = 0;
161         for (nn = 0; nn < FIR_OUTPUT_SIZE; nn++) {
162             if (fir_output[nn] != fir_output_expected[nn]) {
163                 if (++fails < 16)
164                     D("neon[%d] = %d expected %d", nn, fir_output[nn], fir_output_expected[nn]);
165             }
166         }
167         D("%d fails\n", fails);
168     }
169 #else /* !HAVE_NEON */
170     strlcat(buffer, "Program not compiled with ARMv7 support !\n", sizeof buffer);
171 #endif /* !HAVE_NEON */
172 EXIT:
173     //return (*env)->NewStringUTF(env, buffer); // C Version
174     return env->NewStringUTF(buffer); // C++ Version
175 }
176 
177 static JNINativeMethod methods[] = {
178         {"stringFromJNI","()Ljava/lang/String;", (void*) stringforneon },
179 };
180 
181 /*
182  * Register several native methods for one class.
183  */
184 static int registerNativeMethods(JNIEnv* env, const char* className,
185         JNINativeMethod* gMethods, int numMethods) {
186     jclass clazz;
187 
188     clazz = env->FindClass(className);
189     if (clazz == NULL) {
190         D(ANDROID_LOG_INFO, LOG_TAG, "clazz == NULL");
191         return JNI_FALSE;
192     }
193 
194     if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
195         D(ANDROID_LOG_INFO, LOG_TAG,
196                 "RegisterNatives failed for");
197         //LOGE("RegisterNatives failed for '%s'", className);
198         return JNI_FALSE;
199     }
200 
201     return JNI_TRUE;
202 }
203 
204 /*
205  * Register native methods for all classes we know about.
206  *
207  * returns JNI_TRUE on success.
208  */
209 static int registerNatives(JNIEnv* env) {
210     if (!registerNativeMethods(env, classPathName, methods,
211             sizeof(methods) / sizeof(methods[0]))) {
212         return JNI_FALSE;
213     }
214 
215     return JNI_TRUE;
216 }
217 
218 int jniThrowException(JNIEnv* env, const char* className, const char* msg) {
219     jclass exceptionClass = env->FindClass(className);
220     if (exceptionClass == NULL)
221         return -1;
222 
223     if (env->ThrowNew(exceptionClass, msg) != JNI_OK) {
224     }
225 
226     return 0;
227 }
228 JNIEnv* getJNIEnv() {
229     JNIEnv* env = NULL;
230     if (gJVM->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
231         return NULL;
232 
233     return env;
234 }
235 jint JNI_OnLoad(JavaVM* vm, void* reserved) {
236     JNIEnv* env = NULL;
237     jint result = -1;
238     gJVM = vm;
239     D(ANDROID_LOG_INFO, LOG_TAG, "JNI_OnLoad");
240     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
241         return result;
242 
243     if (registerNatives(env) != JNI_TRUE)
244         goto end;
245 
246     result = JNI_VERSION_1_4;
247 
248 end:
249     return result;
250 }
251 
252 #ifdef __cplusplus
253 }
254 #endif
View Code

 

2.其他改动部分同方法一。

不明问题:
stringforneon 的返回类型 只能为 jstring 不能用 string。
参考
http://blog.csdn.net/martingang/article/details/8170940

如果提示错误:error: #error You must enable NEON instructions (e.g. -mfloat-abi=softfp -mfpu=neon) to use arm_neon.h
Android.mk 需要添加两句
1.LOCAL_SRC_FILES := helloneon.cpp 下面添加
TARGET_ARCH_ABI := armeabi-v7a
2.LOCAL_CFLAGS := -DHAVE_NEON=1 后边添加 -mfloat-abi=softfp -mfpu=neon -march=armv7-a
即是  LOCAL_CFLAGS := -DHAVE_NEON=1 -mfloat-abi=softfp -mfpu=neon -march=armv7-a

参考
http://blog.sina.com.cn/s/blog_92c104590101jiyi.html

posted @ 2013-05-21 14:38  水上云天  阅读(2070)  评论(0编辑  收藏  举报