ShareIntroduction
NDK is very useful for developing parts of your Android application in native code. The main motivation is performance.
In this example, I wrote a simple SDK+NDK application that uses the same Fibonacci algorithm implemented both in C and Java. The results in performance are astonishing.
If you want to read more about NDK,
here are 2 usefull articles:
NDK for Performance
The Activity: /src/com/marakana/Fibonacci.javaThis is the activity that specifies a simple UI to enter the number for which we want to compute Fibonacci value. It also provides simple output.
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
package com.marakana; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class Fibonacci extends Activity implements OnClickListener { TextView textResult; Button buttonGo; EditText editInput; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Find UI views editInput = (EditText) findViewById(R.id.editInput); textResult = (TextView) findViewById(R.id.textResult); buttonGo = (Button) findViewById(R.id.buttonGo); buttonGo.setOnClickListener(this); } public void onClick(View view) { int input = Integer.parseInt(editInput.getText().toString()); long start, stop; int result; String out = ""; // Dalvik - Recursive start = System.currentTimeMillis(); result = FibLib.fibJ(input); stop = System.currentTimeMillis(); out += String.format("Dalvik recursive: %d (%d msec)", result, stop - start); // Dalvik - Iterative start = System.currentTimeMillis(); result = FibLib.fibJI(input); stop = System.currentTimeMillis(); out += String.format("\nDalvik iterative: %d (%d msec)", result, stop - start); // Native - Recursive start = System.currentTimeMillis(); result = FibLib.fibN(input); stop = System.currentTimeMillis(); out += String.format("\nNative recursive: %d (%d msec)", result, stop - start); // Native - Iterative start = System.currentTimeMillis(); result = FibLib.fibNI(input); stop = System.currentTimeMillis(); out += String.format("\nNative iterative: %d (%d msec)", result, stop - start); textResult.setText(out); } }
|
The Layout: res/layout/main.xmlThe straight-forward XML layout for the activity above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/app_name" android:gravity="center" android:textSize="40sp" android:layout_margin="10dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/editInput" android:hint="Input" android:textSize="30sp" android:inputType="number" android:layout_margin="10dp"></EditText> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/buttonGo" android:text="Go" android:textSize="30sp" android:layout_margin="10sp"></Button> </LinearLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textResult" android:text="RESULT" android:textSize="20sp"></TextView> </LinearLayout>
|
JNI Interface to Native Code: /src/com/marakana/FibLib.javaThis code represents the JNI interface from Java to the native code. It also provides the pure Java version of Fibonacci function so that we can compare the speed.
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
|
package com.marakana; public class FibLib { // Java implementation - recursive public static int fibJ(int n) { if (n <= 0) return 0; if (n == 1) return 1; return fibJ(n - 1) + fibJ(n - 2); } // Java implementation - iterative public static int fibJI(int n) { int previous = -1; int result = 1; for (int i = 0; i <= n; i++) { int sum = result + previous; previous = result; result = sum; } return result; } // Native implementation static { System.loadLibrary("fib"); } // Native implementation - recursive public static native int fibN(int n); // Native implementation - iterative public static native int fibNI(int n); }
|
Auto-generated JNI Header: /jni/com_marakana_FibLib.hFor how this works, see this
NDK example.
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
|
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_marakana_FibLib */ #ifndef _Included_com_marakana_FibLib #define _Included_com_marakana_FibLib #ifdef __cplusplus extern "C" { #endif /* * Class: com_marakana_FibLib * Method: fibN * Signature: (I)I */ JNIEXPORT jint JNICALL Java_com_marakana_FibLib_fibN (JNIEnv *, jclass, jint); /* * Class: com_marakana_FibLib * Method: fibNI * Signature: (I)I */ JNIEXPORT jint JNICALL Java_com_marakana_FibLib_fibNI (JNIEnv *, jclass, jint); #ifdef __cplusplus } #endif #endif
|
C Implementation of the JNI Header: /jni/fib.cThis is where we provide the actual C version of the Fibonacci function.
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
|
#include "com_marakana_FibLib.h" jint fibN(jint n) { if(n<=0) return 0; if(n==1) return 1; return fibN(n-1) + fibN(n-2); } jint fibNI(jint n) { jint previous = -1; jint result = 1; jint i=0; jint sum=0; for (i = 0; i <= n; i++) { sum = result + previous; previous = result; result = sum; } return result; } JNIEXPORT jint JNICALL Java_com_marakana_FibLib_fibN (JNIEnv *env, jclass obj, jint n) { return fibN(n); } JNIEXPORT jint JNICALL Java_com_marakana_FibLib_fibNI (JNIEnv *env, jclass obj, jint n) { return fibNI(n); }
|
NDK Makefile: /jni/Android.mkAgain, for how this works, see this
NDK example.
1 2 3 4 5 6 7 8
|
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := fib LOCAL_SRC_FILES := fib.c include $(BUILD_SHARED_LIBRARY)
|
Create your library using NDK, and run your app. The result should look like this:
On Emulator
I think the picture is worth 1000 words. There's clearly a huge (order of magnitude) improvement in running certain computation-intensive code outside Dalvik, when running recursively. Iterative computations are much closer together.
Thanks
marakana for this example!!!
Source code files
| File | Description | SDK Version | File size | Last Modified |
Fibonacci.zip | The source code for this example | | 42 Kb | 26/02/11 00:10 |