Использование расширения Intel Cilk Plus для ускорения приложений Android путем использования потоков

Intel(R) CilkTM Plus — это набор языковых расширений для компилятора Intel(R), помогающий легко и быстро применять распараллеливание и векторизацию для кода C/C++. Для ознакомления с базовыми сведениями о Cilk Plus см. главную страницу этого решения.

Intel Cilk Plus: https://software.intel.com/en-us/intel-cilk-plus

Открытый исходный код Cilk Plus: http://www.cilkplus.org/

Цель этой статьи — описание поддержки Cilk Plus в компиляторе Intel C/C++ для Android. Я расскажу о том, как использовать Cilk Plus для повышения производительности ваших приложений в Android.

Три простых ключевых слова:

Intel Cilk Plus содержит 3 простых ключевых слова, помогающих быстро сделать ваше приложение многопоточным. Это ключевые слова cilk_spawn, cilk_sync и cilk_for, но ими возможности Cilk Plus не ограничиваются. Для использования Cilk Plus необходимо слинковать исполняемую библиотеку Cilk (libcilkrts.so).

Использование Cilk Plus в проекте Android NDK
1. Сначала нужно собрать ваш проект в компиляторе Intel. Нужно добавить приведенный ниже код в файл jni/Application.mk (если такого файла нет, его нужно создать):

NDK_TOOLCHAIN = x86-icc
APP_ABI = x86

2. Добавьте подходящую STL в файл Application.mk вашего проекта

APP_STL:=stlport_shared
OR
APP_STL:=gnustl_static
OR
APP_STL:=gnustl_shared

Примечания. После задания STL компилятор Intel автоматически слинкуется с выполняемым модулем Cilk Plus. Если не добавить STL, при сборке кода может появиться много ошибок компоновки вида «ссылка не определена».

3. Загрузка выполняемых библиотек в коде Java

System.loadLibrary("gnustl_shared"); 
System.loadLibrary("cilkrts");
System.loadLibrary("yourJNILib");
OR
System.loadLibrary("stlport_shared");
System.loadLibrary("cilkrts");
System.loadLibrary("yourJNILib");

Где yourJNILib — имя вашей библиотеки JNI. Примечание. В последней версии Android исправлена проблема зависимости loadLibrary. В прежних версиях Android при использовании System.loadLibrary, если libyourJNILib.so зависит от libcilkrts.so, а libcilkrts.so зависит от libgnustl_shared.so, необходимо загружать их, как показано выше. Но при тестировании моего приложения выяснилось, что в последней версии Android эта проблема исправлена, зависимые библиотеки загружаются автоматически и нужно загрузить только вашу библиотеку JNI для приведенного выше кода (нужна только одна строка для загрузки yourJNILib).

4. Использование Cilk Plus в коде C/C++
Теперь можно использовать Cilk Plus в вашем коде. В качестве примера возьмем вычисление последовательности Фибоначчи. Ниже приведены две реализации этого алгоритма:

int fib(int n) {
	if (n == 0 || n == 1)
		return n;
	int x = fib(n - 1);
	int y = fib(n - 2);
	return x + y;
}

#include <cilk/cilk.h>
int fib_cilk(int n) {
	if (n == 0 || n == 1)
		return n;
	int x = cilk_spawn
	fib_cilk(n - 1);
	int y = fib_cilk(n - 2);
	cilk_sync;
	return x + y;
}

Для использования Cilk Plus необходимо включить заголовки. Для трех простых ключевых слов достаточно включить cilk/cilk.h. Назначение cilk_spawn — создание новой ветви (которое можно рассматривать как задачу Cilk Plus), Cilk Plus будет автоматически управлять фактическими рабочими потоками (которые можно рассматривать как физические потоки), а выполняемый модуль будет сопоставлять ветви с рабочими потоками (количество рабочих потоков по умолчанию совпадает с количеством ядер процессора). 

Примечание. В приведенном выше случае код легко понять так: «существует 2 потока, один для выполнения fib_cilk(n-1), а другой для выполнения всего остального кода, т. е. для продолжения кода fib_cilk(n-2)».

Назначение cilk_sync — синхронизация, то есть ожидание завершения всех рабочих потоков, затем продолжение выполнения. Разумеется, для вычисления fib нужно дождаться fib(n-1) и fib(n-2), а затем продолжить выполнение.

Результаты тестирования:

Результаты тестирования таковы: работа кода без Cilk Plus занимает 2831 мс, а код с Cilk Plus работает 10 315 мс. Почему при использовании Cilk Plus код стал работать медленнее? В чем тогда был смысл написания этой статьи?

5. Оптимизация нагрузки

В приведенном выше примере каждый раз при вычислении fib(N) у нас есть два рабочих потока, выполняющих fib(N-1) и fib(N-2). Но если значение N очень маленькое (например, N = 3), то нагрузка fib(N-1) и fib(N-2) будет маленькой, а издержки на создание рабочих потоков и переключение контекста между потоками резко снизят производительность. Такая ситуация возникает постоянно, поэтому издержки будут возникать многократно, а производительность будет намного ниже, чем у кода, не использующего Cilk Plus.

Как решить эту проблему? Нужно пользоваться последовательной обработкой при небольших значениях N. Например:

int fib_cilk_optimize(int n) {
	if (n == 0 || n == 1)
		return n;
	if (n < 20) {
		int x = fib(n - 1);
		int y = fib(n - 2);
		return x + y;
	} else {
		int x = cilk_spawn
		fib_cilk_optimize(n - 1);
		int y = fib_cilk_optimize(n - 2);
		cilk_sync;
		return x + y;
	}
}

Теперь потоки Cilk будут использоваться только для нагрузок, где N >= 20. Результаты тестирования для измененного кода Cilk таковы:

Вот график для приведенных выше результатов:

Примечание. Полный исходный код (проект Android) прилагается в конце этой статьи, его можно загрузить и протестировать на вашем устройстве.



Прочие ресурсы:

https://software.intel.com/en-us/android/articles/using-advanced-intelr-c-compiler-features-for-android-applications

Тестовое устройство: Dell Venue 8 (2 ядра, 4 потока в режиме гиперпоточности) (сведения о том, как получить версию образа этого устройства, предназначенную для разработчиков, см. по адресу http://software.intel.com/en-us/android/articles/mobile-development-kit-for-android

Эта статья применима к следующему:
Продукты: Intel(R) INDE; INTEL(R) System Studio
ОС/платформы разработки: Windows (IA-32, Intel(R) 64), Linux* (IA32, Intel(R) 64)
Целевые ОС/платформы: Android* (IA-32)

Есть файлы для загрузки, доступные на условиях лицензии Intel Sample Source Code License Agreement. Загрузить сейчас
Пожалуйста, обратитесь к странице Уведомление об оптимизации для более подробной информации относительно производительности и оптимизации в программных продуктах компании Intel.
Возможность комментирования русскоязычного контента была отключена. Подробнее. Закон о блогерах