使用 Intel® Threading Building Blocks 计算 pi





0/5 (0投票)
英特尔开发了一款用于开发并行应用程序的宝贵工具,名为 Intel® Threading Building Blocks (Intel® TBB)。
Intel® Developer Zone 提供跨平台应用开发工具和操作指南、平台和技术信息、代码示例以及同行专业知识,以帮助开发人员创新并取得成功。加入我们的社区,获取 Android、物联网、Intel® RealSense™ 技术和 Windows 的相关信息,下载工具,访问开发套件,与志同道合的开发者交流想法,并参与黑客松、竞赛、路演和本地活动。
许多 Android* 设备都有多核处理器,了解如何开发多线程应用程序在移动行业变得越来越重要。英特尔开发了一款用于开发并行应用程序的宝贵工具,名为 Intel® Threading Building Blocks (Intel® TBB)。Intel® TBB 是一个用于创建并行程序的模板的跨平台库。它创建和同步数据流,隐藏了架构的细节,让您可以在更高的抽象级别上工作。Intel® TBB 可在所有架构上运行。对于 Android,请使用 4.3 及以上版本。
构建 Intel® TBB
- 下载 TBB。您可以在此处下载 Intel® TBB:https://www.threadingbuildingblocks.org/。我下载了最后一个稳定版本 (4.3 Update 1) 的源代码。
- 将 NDK 添加到 PATH
对于 Windows*$ SET PATH=%PATH%;
$ export PATH=$PATH
- 解压 TBB 并进入包含源代码的目录,然后在 src 文件夹中。
$ cd /src/
- 运行 TBB for Android:
$ /ndk-build –C /src/ arch=intel64 compiler=gcc target=android clean tbb tbbmalloc –j
此命令构建 64 位 Android 版 TBB。要构建 32 位 Android 版 TBB,请将arch=intel64
更改为arch=ia32
。它将为 Android 64 位架构构建应用程序。 - 库已构建。在 build 目录 (/build/) 中,您可以找到包含 libs 的目录:
libgnustl_shared.so, libtbbmalloc_proxy.so, libtbbmalloc.so 和 libtbb.so。 libtbb.so 和 libgnustl_shared
. so 将在我们的应用程序中使用。
计算 π
要计算 π,您可以从 Wikipedia 中选择任何带有定积分的公式:https://en.wikipedia.org/wiki/List_of_formulae_involving_%CF%80#Integrals。我选择了这个公式
对于这个程序,我修改了公式:对于这个程序,我修改了公式:对于这个程序,我修改了公式
对于积分计算,我使用了矩形法。被积函数被分成 N = 107 个相等的子区间,长度为 h = 2·10-7。然后通过将 N 个矩形的面积(底乘以高)相加来计算积分的近似值,得到公式
创建应用程序
要创建一个新的 Android 应用程序
创建主活动
在 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="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>
在 res/values/strings.xml
中添加此代码
<?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>
现在主活动看起来是这样的
接下来,我们需要为我们的活动实现 Java* 接口。在 src/intel.example.pitbbcalc/MainActivity.java
文件中,添加以下代码
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);
}
}
我们可以通过在项目浏览器中右键单击我们的项目 -> Android Tools -> Add Native Support 来添加本地支持。
在下一个窗口中输入我们项目的库名称,然后单击 Finish。
现在我们必须在单个线程中实现积分计算的本地代码。在 jni/PiTBBCalc.cpp
文件中,添加以下代码
#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();
}
让我们尝试运行我们的应用程序,并在单线程模式下计算 π。
要将 Intel® TBB 的并行实现添加到我们的项目中,我们应该编辑 jni/Android.mk
。Android.mk 是我们项目的 Makefile,我们需要将 Intel® 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 := 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)
在 jni/
目录中,创建一个 Application.mk
文件并添加以下行
APP_ABI := x86_64 APP_GNUSTL_FORCE_CPP_FEATURES := exceptions rtti APP_STL := gnustl_shared
Application.mk 的目的是描述您的应用程序需要哪些本地模块(即静态/共享库)。在 APP_ABI := x86_64
行中,我们指定了目标架构。
现在我们可以尝试运行我们的应用程序。如果您看到应用程序的主屏幕,则表示 Intel® TBB 已成功链接,我们可以开始开发我们的应用程序了。
要为代码添加并行性,我们应该包含 Intel® TBB 头文件:#include "tbb/tbb.h"
,删除循环并添加以下代码
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
}
);
现在,如果您运行该应用程序,它将以多线程模式工作。
摘要
正如您所见,开发并行应用程序非常容易。以 π 的计算为例,我们已经成功演示了如何将此处从单线程代码到多线程代码的概念应用起来。