Quantcast
Channel: 英特尔开发人员专区文章
Viewing all articles
Browse latest Browse all 583

基于64位架构使用英特尔® 线程构建模块并行化安卓* 应用

$
0
0

全新的 Android L 64 位操作系统已于近日推出。 在本文中,我将向您展示如何利用英特尔® 线程构建模块(英特尔® TBB)轻松地开发面向 Android L 64 位架构的并行应用。 英特尔® TBB 是一个跨平台模板库,可用于创建并行程序。 它可以创建和同步数据流,同时隐藏架构详情,支持您在更高的抽象化水平上工作。 英特尔® TBB 可以在所有架构上运行。 对于 Android,请使用 4.3 及更高版本。

构建英特尔® TBB

  1. 您可以在此处下载英特尔® TBB: https://www.threadingbuildingblocks.org/. 我下载了最新的稳定版(4.3 Update 1)。
  2. 将 NDK 添加至路径:
    对于 Windows*:
    • $ SET PATH=%PATH%; <path_to_ndk>
    对于 Linux*:
    • $ export PATH=$PATH: <path_to_ndk>
  3. 解压 TBB,转至 src 文件夹。
    $ cd <tbb_sources>/src/
  4. 通过运行以下代码构建面向 Android 的英特尔 TBB 库: $ <path_to_ndk>/ndk-build –C <tbb_sources>/src/ arch=intel64 compiler=gcc target=android clean tbb tbbmalloc -j
  5. 库构建完成。 在 build 目录 (<tbb_sources>/build/) 中,您可以找到包含这些 libs 的目录: libgnustl_shared.so, libtbbmalloc_proxy.so, libtbbmalloc.so and libtbb.so. libtbb.so and libgnustl_shared。 我们会在应用中用到 libtbb.so 和 libgnustl_shared.so。

配置仿真器

在 Eclipse* 中点击: Window -> Android Virtual Device Manager. 在该窗口中点击 Create 并在下一个界面上选择显示的选项:

点击 Ok。 如要检查它是否工作,选择列表中的新设备并点击 Start... 在新窗口中,点击 Launch 按钮启动仿真器:

创建应用

在我们的样本应用中,我们会采用矩阵相乘 (3x2) 乘以 (2x3)。 让我们开始吧!

创建一个新的 Android 应用:

通过右击我们在 Project Explorer -> Android Tools -> Add Native Support 中的项目,我们可以添加本地支持。

在下一个窗口中输入项目库的名称并点击 Finish

在项目目录中,一个新的 jni 目录创建完成了。 Android.mk 是项目的生成文件,我们需要将英特尔® TBB 库添加到这个文件中:

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    := TBBMatrixMult
LOCAL_SRC_FILES := TBBMatrixMult.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)

在 jni 目录中,创建一个 Application.mk 文件并添加以下行:

APP_ABI := x86_64
APP_GNUSTL_FORCE_CPP_FEATURES := exceptions rtti
APP_STL := gnustl_shared

Application.mk 用于描述您的应用需要哪些原生模块(即静态/共享库)。 在行 APP_ABI := x86_64中,我们可以指定我们的目标架构。 它会创建面向 64 位架构的应用。

现在我们可以尝试运行我们的应用。 如果您看到了应用的主界面,那就表明英特尔® TBB 链接成功了,我们可以开始开发我们的矩阵乘法应用了。

res/layout/activity_main.xml中粘贴以下代码:

<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=".MainActivity"><ScrollView
        android:id="@+id/scrollView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"><TextView
                android:id="@+id/titleA"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="16dp"
                android:text="@string/a"
                android:textAppearance="?android:attr/textAppearanceSmall" /><LinearLayout
		        android:layout_width="match_parent"
		        android:layout_height="wrap_content"><EditText
		            android:id="@+id/a00"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /><EditText
		            android:id="@+id/a01"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned"><requestFocus /></EditText></LinearLayout><LinearLayout
		        android:layout_width="match_parent"
		        android:layout_height="wrap_content"><EditText
		            android:id="@+id/a10"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /><EditText
		            android:id="@+id/a11"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /></LinearLayout><LinearLayout
		        android:layout_width="match_parent"
		        android:layout_height="wrap_content"><EditText
		            android:id="@+id/a20"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /><EditText
		            android:id="@+id/a21"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /></LinearLayout><TextView
		        android:id="@+id/titleB"
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:layout_marginTop="15dp"
		        android:text="@string/b"
		        android:textAppearance="?android:attr/textAppearanceSmall" /><LinearLayout
		        android:layout_width="match_parent"
		        android:layout_height="wrap_content"><EditText
		            android:id="@+id/b00"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /><EditText
		            android:id="@+id/b01"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /><EditText
		            android:id="@+id/b02"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /></LinearLayout><LinearLayout
		        android:layout_width="match_parent"
		        android:layout_height="wrap_content"><EditText
		            android:id="@+id/b10"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /><EditText
		            android:id="@+id/b11"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /><EditText
		            android:id="@+id/b12"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_weight="1"
		            android:ems="3"
		            android:inputType="numberDecimal|numberSigned" /></LinearLayout><Button
		        android:id="@+id/button"
		        style="?android:attr/buttonStyleSmall"
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:layout_marginTop="17dp"
		        android:text="@string/button" /><TextView
		        android:id="@+id/titleC"
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:text="@string/c"
		        android:textAppearance="?android:attr/textAppearanceSmall" /><LinearLayout
		        android:layout_width="match_parent"
		        android:layout_height="wrap_content"><TextView
		            android:id="@+id/c00"
		            android:layout_width="70dp"
		            android:layout_height="wrap_content"
		            android:textAppearance="?android:attr/textAppearanceSmall" /><TextView
		            android:id="@+id/c01"
		            android:layout_width="70dp"
		            android:layout_height="wrap_content"
		            android:textAppearance="?android:attr/textAppearanceSmall" /><TextView
		            android:id="@+id/c02"
		            android:layout_width="70dp"
		            android:layout_height="wrap_content"
		            android:textAppearance="?android:attr/textAppearanceSmall" /></LinearLayout><LinearLayout
		        android:layout_width="match_parent"
		        android:layout_height="wrap_content"><TextView
		            android:id="@+id/c10"
		            android:layout_width="70dp"
		            android:layout_height="wrap_content"
		            android:textAppearance="?android:attr/textAppearanceSmall" /><TextView
		            android:id="@+id/c11"
		            android:layout_width="70dp"
		            android:layout_height="wrap_content"
		            android:textAppearance="?android:attr/textAppearanceSmall" /><TextView
		            android:id="@+id/c12"
		            android:layout_width="70dp"
		            android:layout_height="wrap_content"
		            android:textAppearance="?android:attr/textAppearanceSmall" /></LinearLayout><LinearLayout
		        android:layout_width="match_parent"
		        android:layout_height="wrap_content"><TextView
		            android:id="@+id/c20"
		            android:layout_width="70dp"
		            android:layout_height="wrap_content"
		            android:layout_marginBottom="40dp"
		            android:textAppearance="?android:attr/textAppearanceSmall" /><TextView
		            android:id="@+id/c21"
		            android:layout_width="70dp"
		            android:layout_height="wrap_content"
		            android:textAppearance="?android:attr/textAppearanceSmall" /><TextView
		            android:id="@+id/c22"
		            android:layout_width="70dp"
		            android:layout_height="wrap_content"
		            android:textAppearance="?android:attr/textAppearanceSmall" /></LinearLayout></LinearLayout></ScrollView></RelativeLayout>

res/values/strings.xml中添加以下代码:

<?xml version="1.0" encoding="utf-8"?><resources><string name="app_name">TBBMatrixMult</string><string name="action_settings">Settings</string><string name="a">A:</string><string name="b">B:</string><string name="c">C:</string><string name="button">A x B = C</string></resources>

现在我们的主活动如下所示:

 

接下来我们需要为我们的活动实施 Java* 接口。 在 src/intel.example.tppmatrixmult/MainActivity.java 文件中添加以下代码:

package intel.example.tbbmatrixmult;

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;
import android.widget.Toast;

public class MainActivity extends Activity {

	private native double [][] onClickCalc(double [] a, double [] b, int aRow, int aCol);
	private EditText matrixA [][] = new EditText[3][2];
	private EditText matrixB [][] = new EditText[2][3];
	private TextView matrixC [][] = new TextView[3][3];
	private TextView titleC;
	private Button mult;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		initA();
		initB();
		initC();
		mult = (Button) findViewById(R.id.button);
		mult.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Toast.makeText(getBaseContext(), "Unknown error!", Toast.LENGTH_SHORT).show();
				double [][] a = getA();
				double [][] b = getB();
				if (a == null || b == null) {
					Toast.makeText(getBaseContext(), "Unknown error!", Toast.LENGTH_SHORT).show();
					return;
				}
				double [][] c = onClickCalc(matrixToArray(a), matrixToArray(b), 3, 2);
				setC(c);
				setVisibleC(true);
			}
		});
		setVisibleC(false);

		System.loadLibrary("tbb");
        System.loadLibrary("TBBMatrixMult");
	}

	private double [] matrixToArray(double [][] matrix) {
		double [] array = new double[matrix.length * matrix[0].length];
		for (int row = 0; row < matrix.length; ++row) {
			for (int col = 0; col < matrix[row].length; ++col)
			{
				array[row * matrix[row].length + col] = matrix[row][col];
			}
		}
		return array;
	}

	private void initA() {
		matrixA[0][0] = (EditText) findViewById(R.id.a00);
		matrixA[0][1] = (EditText) findViewById(R.id.a01);
		matrixA[1][0] = (EditText) findViewById(R.id.a10);
		matrixA[1][1] = (EditText) findViewById(R.id.a11);
		matrixA[2][0] = (EditText) findViewById(R.id.a20);
		matrixA[2][1] = (EditText) findViewById(R.id.a21);
	}
	private void initB() {
		matrixB[0][0] = (EditText) findViewById(R.id.b00);
		matrixB[0][1] = (EditText) findViewById(R.id.b01);
		matrixB[0][2] = (EditText) findViewById(R.id.b02);
		matrixB[1][0] = (EditText) findViewById(R.id.b10);
		matrixB[1][1] = (EditText) findViewById(R.id.b11);
		matrixB[1][2] = (EditText) findViewById(R.id.b12);
	}
	private void initC() {
		titleC = (TextView) findViewById(R.id.titleC);
		matrixC[0][0] = (TextView) findViewById(R.id.c00);
		matrixC[0][1] = (TextView) findViewById(R.id.c01);
		matrixC[0][2] = (TextView) findViewById(R.id.c02);
		matrixC[1][0] = (TextView) findViewById(R.id.c10);
		matrixC[1][1] = (TextView) findViewById(R.id.c11);
		matrixC[1][2] = (TextView) findViewById(R.id.c12);
		matrixC[2][0] = (TextView) findViewById(R.id.c20);
		matrixC[2][1] = (TextView) findViewById(R.id.c21);
		matrixC[2][2] = (TextView) findViewById(R.id.c22);
	}

	private double[][] getA() {
		double [][] ret = new double [matrixA.length][];
		for (int i = 0; i < matrixA.length; ++i) {
			ret[i] = new double [matrixA[i].length];
			for (int j = 0; j < matrixA[i].length; ++j) {
				if (matrixA[i][j].getText().toString().length() == 0) {
					Toast.makeText(getBaseContext(), "Error! One field is empty!", Toast.LENGTH_SHORT).show();
					return null;
				}
				ret[i][j] = Double.parseDouble(matrixA[i][j].getText().toString());
			}
		}
		return ret;
	}

	private double[][] getB() {
		double [][] ret = new double [matrixB.length][];
		for (int i = 0; i < matrixB.length; ++i) {
			ret[i] = new double [matrixB[i].length];
			for (int j = 0; j < matrixB[i].length; ++j) {
				if (matrixB[i][j].getText().toString().length() == 0) {
					Toast.makeText(getBaseContext(), "Error! One field is empty!", Toast.LENGTH_SHORT).show();
					return null;
				}
				ret[i][j] = Double.parseDouble(matrixB[i][j].getText().toString());
			}
		}
		return ret;
	}

	private void setC(double [][] cVal) {
		if (matrixC.length != cVal.length) {
			Toast.makeText(getBaseContext(), "Unknown error!", Toast.LENGTH_SHORT).show();
			return;
		}
		for (int i = 0; i < matrixC.length; ++i) {
			if (matrixC[i].length != cVal[i].length) {
				Toast.makeText(getBaseContext(), "Unknown error!", Toast.LENGTH_SHORT).show();
				return;
			}
			for (int j = 0; j < matrixC[i].length; ++j) {
				matrixC[i][j].setText(String.valueOf(cVal[i][j]));
			}
		}
	}

	private void setVisibleC(boolean cond) {
		if (cond == true)
			titleC.setVisibility(View.VISIBLE);
		else
			titleC.setVisibility(View.GONE);
		for (int i = 0; i < matrixC.length; ++i) {
			for (int j = 0; j < matrixC[i].length; ++j) {
				if (cond == true) {
					matrixC[i][j].setVisibility(View.VISIBLE);
				}
				else {
					matrixC[i][j].setVisibility(View.GONE);
				}
			}
		}
	}
}

现在我们正在使用面向并行代码的英特尔 TBB 构建。 下一个代码片段是 jni/TBBMatrixMult.cpp中的矩阵乘法实施。 该代码在单线程下运行:

#include <jni.h>

double ** arrayToMatrix(double * array, int row, int col)
{
	double ** matrix = new double * [row];
	for (int i = 0; i < row; ++i)
	{
		matrix[i] = new double [col];
		for (int j = 0; j < col; ++j)
		{
			matrix[i][j] = array[i * col + j];
		}
	}
	return matrix;
}

extern "C" JNIEXPORT jobjectArray JNICALL Java_intel_example_tbbmatrixmult_MainActivity_onClickCalc(
		JNIEnv *env, jobject obj, jdoubleArray aMatrix, jdoubleArray bMatrix, jint aRow, jint aCol)
{
	double * aArray = (*env).GetDoubleArrayElements(aMatrix, 0);
	double ** a = arrayToMatrix(aArray, aRow, aCol);
	double * bArray = (*env).GetDoubleArrayElements(bMatrix, 0);
	double ** b = arrayToMatrix(bArray, aCol, aRow);
	double ** c = new double * [aRow];
	for (int i = 0 ; i < 3; ++i) {
		c[i] = new double [aRow];
	}
	for (int row = 0; row < aRow, ++row) {
		for (int col = 0; col < aRow; ++col) {
			c[row][col] = 0;
			for(int k = 0; k < aCol; ++k)
			{
				c[row][col] += a[row][k] * b[k][col];
			}
		}
	};

	jclass doubleArrayClass = (*env).FindClass("[D");

	jobjectArray cMatrix = (*env).NewObjectArray((jsize) aRow, doubleArrayClass, 0);

	for (int i = 0; i < aRow; i++)
	{
		jdoubleArray doubleArray = (*env).NewDoubleArray(aRow);
		(*env).SetDoubleArrayRegion(doubleArray, (jsize) 0, (jsize) aRow, c[i]);
		(*env).SetObjectArrayElement(cMatrix, (jsize) i, doubleArray);
		(*env).DeleteLocalRef(doubleArray);
	}

	return cMatrix;
}
For adding parallelism to this code, we should include the Intel TBB header: #include "tbb/tbb.h" and change the cycle by row:
tbb::parallel_for (0, aRow, 1, [=](int row) {
	for (int col = 0; col < aRow; ++col) {
		c[row][col] = 0;
		for(int k = 0; k < aCol; ++k)
		{
			c[row][col] += a[row][k] * b[k][col];
		}
	}
});

现在我们正在使用面向并行代码的英特尔 TBB 构建。 下一个代码片段是 jni/TBBMatrixMult.cpp 中的矩阵乘法实施。 该代码在单线程下运行:

#include <jni.h>

double ** arrayToMatrix(double * array, int row, int col)
{
	double ** matrix = new double * [row];
	for (int i = 0; i < row; ++i)
	{
		matrix[i] = new double [col];
		for (int j = 0; j < col; ++j)
		{
			matrix[i][j] = array[i * col + j];
		}
	}
	return matrix;
}

extern "C" JNIEXPORT jobjectArray JNICALL Java_intel_example_tbbmatrixmult_MainActivity_onClickCalc(
		JNIEnv *env, jobject obj, jdoubleArray aMatrix, jdoubleArray bMatrix, jint aRow, jint aCol)
{
	double * aArray = (*env).GetDoubleArrayElements(aMatrix, 0);
	double ** a = arrayToMatrix(aArray, aRow, aCol);
	double * bArray = (*env).GetDoubleArrayElements(bMatrix, 0);
	double ** b = arrayToMatrix(bArray, aCol, aRow);
	double ** c = new double * [aRow];
	for (int i = 0 ; i < 3; ++i) {
		c[i] = new double [aRow];
	}
	for (int row = 0; row < aRow, ++row) {
		for (int col = 0; col < aRow; ++col) {
			c[row][col] = 0;
			for(int k = 0; k < aCol; ++k)
			{
				c[row][col] += a[row][k] * b[k][col];
			}
		}
	};

	jclass doubleArrayClass = (*env).FindClass("[D");

	jobjectArray cMatrix = (*env).NewObjectArray((jsize) aRow, doubleArrayClass, 0);

	for (int i = 0; i < aRow; i++)
	{
		jdoubleArray doubleArray = (*env).NewDoubleArray(aRow);
		(*env).SetDoubleArrayRegion(doubleArray, (jsize) 0, (jsize) aRow, c[i]);
		(*env).SetObjectArrayElement(cMatrix, (jsize) i, doubleArray);
		(*env).DeleteLocalRef(doubleArray);
	}

	return cMatrix;
}

向代码添加并行功能时,我们应加上英特尔® TBB 标题: #include"tbb/tbb.h"并逐行更改周期:

tbb::parallel_for (0, aRow, 1, [=](int row) {
	for (int col = 0; col < aRow; ++col) {
		c[row][col] = 0;
		for(int k = 0; k < aCol; ++k)
		{
			c[row][col] += a[row][k] * b[k][col];
		}
	}
});

您可以在下一个屏幕截图上看到我们应用的结果:


Viewing all articles
Browse latest Browse all 583

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>