Вычисление числа Пи с помощью Intel Threading Building Blocks

от автора

Многие Android-устройства используют процессоры с несколькими вычислительными ядрами, поэтому в отрасли разработки мобильных приложений всё более важным становится умение создавать многопоточные программы. Компания Intel предлагает ценный инструментарий для разработки «параллельных» приложений – он называется Intel Threading Building Blocks (Intel TBB). По существу, Intel TBB представляет собой кросс-платформенную библиотеку шаблонов для создания параллельных программ. Она позволяет создавать и синхронизировать потоки данных, оставляя за кадром детали архитектуры и позволяя вам работать на высоком уровне абстрагирования. Intel TBB поддерживает все архитектуры. Что касается ОС Android, то следует использовать версию 4.3 и выше.

image

Создание Intel TBB

  1. Скачайте Intel TBB, найти можно здесь: www.threadingbuildingblocks.org.
  2. Добавьте NDK в PATH. Для Windows:
    $ SET PATH=%PATH%;

    Для Linux:

    $ export PATH=$PATH:

  3. Распакуйте TBB и перейдите в директорию с исходным кодом и в папку src.
    $ cd /src/

  4. Запустите TBB для Android:
    $ /ndk-build –C /src/ arch=intel64 compiler=gcc target=android clean tbb tbbmalloc –j

    Эта команда создает TBB для 64-разрядной версии Android 64. Чтобы сформировать TBB для 32-разрядной версии Android, замените arch=intel64 на arch=ia32.

  5. Библиотека создана. В соответствующей директории (/build/) вы найдете поддиректории с библиотеками: libgnustl_shared.so, libtbbmalloc_proxy.so, libtbbmalloc.so and libtbb.so. libtbb.so и libgnustl_shared. Теперь их можно использовать в нашем приложении.

Вычисление числа Пи

Для вычисления Пи можно выбрать в Wikipedia любую формулу с определенным интегралом. Я выбрал следующую формулу:

image

Для данной программы я модифицировал эту формулу:

image

Для вычисления интеграла я использовал метод прямоугольников. Интегрируемая функция разбивается на N = 107 равных подинтервалов длиной h = 2·10-7. Затем вычисляется аппроксимация интеграла – сложением площадей (основание х высоту) N прямоугольников по формуле:

image

Создание приложения

Создадим новое Android-приложение:

image

Создадим «основную активность» (Main Activity). Копируем следующий код в 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>

Теперь Main Activity выглядит примерно так:

image

Далее нам нужно реализовать для своей активности интерфейс 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 автоматически генерируемая заглушка 				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) { 		// заполнение меню; добавление элементов в строку действий, если есть. 		getMenuInflater().inflate(R.menu.main, menu); 		return true; 	}  	@Override 	public boolean onOptionsItemSelected(MenuItem item) { 	        // Обработка элементов строки действий. Действия будут 		// автоматически обрабатывать щелчки мышью на Home/Up, если 		// в AndroidManifest.xml задается родительское действие. 		int id = item.getItemId(); 		if (id == R.id.action_settings) { 			return true; 		} 		return super.onOptionsItemSelected(item); 	} }

В Project Explorer -> Android Tools -> Add Native Support можно задать нативную поддержку нажатия правой кнопкой на нашем проекте. В следующем окне вводим имя библиотеки нашего проекта и щёлкаем мышью на Finish.

image

Итак, мы реализовали нативный код для вычисления интеграла в одном потоке. В файл 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(); }

Попробуем запустить наше приложение и вычислить число Пи в однопоточном режиме:

image

Чтобы с помощью 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), // элемент для суммирования 		[&](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; // тело возвращает обновленное значение для накопителя 		}, 		[]( double x, double y )->double { 			return x+y; // соединяет два накопленных значения 		} 	);

И теперь, если запустить приложение, оно будет работать в многопоточном режиме.

The end

Как видите, разработка параллельных приложений очень проста. Используя в качестве примера вычисление числа Пи, мы смогли успешно продемонстрировать, как концепции однопоточного кода применяются в многопоточном коде.

Хозяйке на заметку:

» Threading Building Blocks – базовые элементы многопоточности
» Создание параллельных Android-приложений для 64-разрядной архитектуры с использованием Intel TBB
» Руководство по Android: написание многопоточных приложений с помощью Intel Threading Building Blocks

ссылка на оригинал статьи http://habrahabr.ru/post/260083/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *