Many Android* devices have processors with more than one core and knowing how to develop multithreaded applications has become important in the mobile industry. Intel has developed a valuable tool for developing parallel applications called Intel® Threading Building Blocks (Intel® TBB). The Intel® TBB is a cross-platform library of templates for creating parallel programs. It creates and synchronizes streams of data, hiding the details of the architecture and allowing you to work at a higher level of abstraction. Intel® TBB works on all architectures. For Android, use version 4.3 and above.
Build Intel® TBB
- Download TBB. You can download Intel® TBB here: https://www.threadingbuildingblocks.org/. I downloaded the sources of the last stable release (4.3 Update 1).
- Add NDK to PATH:
For Windows*:$ SET PATH=%PATH%;
$ export PATH=$PATH:
- Unzip TBB and go to the directory with source code and in src folder.
$ cd /src/
- Run TBB for Android:
$ /ndk-build –C /src/ arch=intel64 compiler=gcc target=android clean tbb tbbmalloc –j
This command builds TBB for Android 64 bit. For building TBB for Android 32 bit, changearch=intel64 on arch=ia32
. It will build the application for Android 64 bit architecture. - The library is built. In build directory (/build/) you can find directories with libs:
libgnustl_shared.so, libtbbmalloc_proxy.so, libtbbmalloc.so and libtbb.so. libtbb.so and libgnustl_shared
. so we will use in our application.
Calculate π
To calculate π you can choose any formula with a definite integral from Wikipedia: https://en.wikipedia.org/wiki/List_of_formulae_involving_%CF%80#Integrals. I chose this formula:
For this program I modified the formula:For this program I modified the formula:For this program I modified the formula:
For integral calculating I used the rectangle method. The integrated function is divided into N = 107 equal subintervals of length h = 2·10-7. The approximation to the integral is then calculated by adding up the areas (base multiplied by height) of the N rectangles, giving the formula:
Create Application
To create a new Android application:
Create Main Activity
In the res/layout/activity_main.xml
paste the following code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="intel.example.pitbbcalc.MainActivity"><LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"><TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/title" android:textAppearance="?android:attr/textAppearanceLarge" /><Button android:id="@+id/startButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/start" /><LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"><TextView android:id="@+id/pi_equally" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/pi_equally" android:textAppearance="?android:attr/textAppearanceLarge" /><TextView android:id="@+id/pi_val" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" /></LinearLayout></LinearLayout></RelativeLayout>
In the res/values/strings.xml
add this code:
<?xml version="1.0" encoding="utf-8"?><resources><string name="app_name">PiTBBCalc</string><string name="action_settings">Settings</string><string name="start">Start</string><string name="title">Calculation of π</string><string name="pi_equally">π = </string></resources>
Now the main activity looks like this:
Next we need to implement the Java* interface for our activity. In the src/intel.example.pitbbcalc/MainActivity.java
file, add the following code:
package intel.example.pitbbcalc; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private native double onClickCalc(); private TextView piEqually; private TextView piVal; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button startButton = (Button) findViewById(R.id.startButton); piEqually = (TextView) findViewById(R.id.pi_equally); piVal = (TextView) findViewById(R.id.pi_val); piEqually.setVisibility(View.INVISIBLE); piVal.setVisibility(View.INVISIBLE); startButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub double val = onClickCalc(); piVal.setText(String.valueOf(val)); piEqually.setVisibility(View.VISIBLE); piVal.setVisibility(View.VISIBLE); } }); System.loadLibrary("PiTBBCalc"); System.loadLibrary("tbb"); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
We can add native support by right-clicking on our project in Project Explorer -> Android Tools -> Add Native Support.
On the next window enter the name of the lib of our project and click Finish.
Now we have to implement native code for integral calculating in one thread. In the jni/PiTBBCalc.cpp
file, add the following code:
#include <jni.h> #include <math.h> double piIntFunc (const double x) { return sqrt(1 - pow(x, 2.0)); } double calcPi() { const unsigned int n = pow(10.0, 7); double a(-1), b(1); double h = (b - a) / n; double x (a); for (unsigned int i (0); i < n; ++i) { sum += piIntFunc(x); x += h; } sum *= h; return 2 * sum; } extern "C" JNIEXPORT jdouble JNICALL Java_intel_example_pitbbcalc_MainActivity_onClickCalc(JNIEnv *env, jobject obj) { return calcPi(); }
Let’s try running our application and π calculation in single threaded mode.
To add parallel implementation with Intel® TBB to our project we should edit jni/Android.mk
. Android.mk is the Makefile for our project, and we need to add the Intel® TBB libs to it:
LOCAL_PATH := $(call my-dir) TBB_PATH := <tbb_sources> TBB_BUILD_PATH := /build/linux_intel64_gcc_android_cc4.9_NDKr10b_version_android-L_release include $(CLEAR_VARS) LOCAL_MODULE := PiTBBCalc LOCAL_SRC_FILES := PiTBBCalc.cpp LOCAL_CFLAGS += -DTBB_USE_GCC_BUILTINS -std=c++11 -fexceptions -Wdeprecated-declarations -I$(TBB_PATH)/include -I$(TBB_PATH)$(TBB_BUILD_PATH) LOCAL_LDLIBS := -llog -ltbb -L./ -L$(TBB_PATH)$(TBB_BUILD_PATH) LOCAL_SHARED_LIBRARIES += libtbb include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libtbb LOCAL_SRC_FILES := $(TBB_PATH)$(TBB_BUILD_PATH)/libtbb.so include $(PREBUILT_SHARED_LIBRARY)
In the jni/
directory, create an Application.mk
file and add the following lines:
APP_ABI := x86_64 APP_GNUSTL_FORCE_CPP_FEATURES := exceptions rtti APP_STL := gnustl_shared
The purpose of Application.mk is to describe which native modules (i.e., static/shared libraries) are needed by your application. In the line APP_ABI := x86_64
we specify our target architecture.
Now we can try to run our application. If you see the main screen of the application, then Intel® TBB linked successfully and we can start developing our app.
For adding parallelism to the code, we should include the Intel® TBB header: #include "tbb/tbb.h"
, remove the cycle and add the following code:
double sum = tbb::parallel_reduce( tbb::blocked_range<unsigned int>(0,n), double(0), // identity element for summation [&](const tbb::blocked_range<unsigned int>& r, double sum)->double { for( int i=r.begin(); i!=r.end(); ++i ) { sum += piIntFunc(x); x += h; } return sum; // body returns updated value of accumulator }, []( double x, double y )->double { return x+y; // joins two accumulated values } );
And now, if you run the application it will work in multithreaded mode.
Summary
As you can see, developing parallel applications is very easy. By using the calculation of π as an example we were able to successfully demonstrate how to apply the concepts here from single-threaded code to multithreaded code.