Использование Renderscript на android-устройствах с процессорами Intel®

от автора

image

В статье я хотел бы дать краткое описание работы технологии Renderscript внутри Android, сравнить ее производительность с Dalvik на конкретном примере аndroid-устройства с процессором Intel и рассмотреть небольшой прием оптимизации renderscript.
Renderscript – это API, который включает функции для 2D/3D рендеринга и математических вычислений с высокой производительностью. Он позволяет описать какую-либо задачу с однотипными независимыми вычислениями над большим объемом данных и разбить ее на однородные подзадачи, которые могут быть выполнены быстро и параллельно на многоядерных Android-платформах.
Такая технология может повысить производительность ряда dalvik приложений, связанных с обработкой изображений, распознаванием образов, физическим моделированием, клеточно-автоматной моделью и др., которые, в свою очередь, не потеряют аппаратной независимости.

1. Технология Renderscript внутри Android

Приведу краткий обзор механизма работы технологии Renderscript внутри Android, ее достоинства и недостатки.

1.1 Renderscript offline-компиляция

Renderscript начал поддерживаться в Honeycomb/Android 3.0 (API 11). А именно, в Android SDK в директории platform-tools появился llvm-rs-cc (offline compiler) для компиляции renderscript (*.rs файл) в байт-код (*.bc файл) и генерации java классов объектов (*.java файлы) для структур, глобальных переменных внутри renderscript и самого renderscript. В основе llvm-rs-cc лежит Clang компилятор с небольшими изменениями под Android, который представляет собой front-end для LLVM компилятора.
image

1.2 Renderscript run-time компиляция

В Android появился framework, построенный на базе LLVM back-end, который отвечает за run-time компиляцию байт-кода, линковку с нужными библиотеками, запуск и контроль выполнения renderscript. Этот framework состоит из следующих частей: libbcc занимается инициализацией LLVM контекста в соответствии с указанными прагмами и другими метаданными в байт-коде, компиляцией байт-кода и динамической линковкой с нужными библиотеками из libRS; libRS содержит реализацию библиотек (math, time, drawing, ref-counting,…), структур и типов данных (Script, Type, Element, Allocation, Mesh, various matrices,…).

image
Преимущества:

  • Аппаратно-независимое приложение получается за счет того, что renderscript байт-код, входящий в apk файл, в run-time будет скомпилирован в машинный код того аппаратно-вычислительного модуля (CPU) платформы, где будет запущен;
  • Быстрота исполнения достигается благодаря распараллеливанию вычислений, run-time компиляторной оптимизации и нативному исполнению кода.

Недостатки:

  • Отсутствие подробной документации для работы с renderscript усложняет разработку приложений. Все ограничивается коротким описанием предлагаемого renderscript run-time API, представленного здесь;
  • Отсутствие поддержки исполнения renderscript потоков на GPU, DSP. Возможны проблемы с run-time балансировкой потоков в гетерогенном запуске, управлением общей памятью.

2. Dalvik vs. Renderscript в монохромной обработке изображения

Рассмотрим dalvik-функцию Dalvik_MonoChromeFilter (преобразование цветного RGB-изображения в черно-белое (монохромное) ):

private void Dalvik_MonoChromeFilter() {     	float MonoMult[] = {0.299f, 0.587f, 0.114f};     	int mInPixels[] = new int[mBitmapIn.getHeight() * mBitmapIn.getWidth()];     	int mOutPixels[] = new int[mBitmapOut.getHeight() * mBitmapOut.getWidth()];     	mBitmapIn.getPixels(mInPixels, 0, mBitmapIn.getWidth(), 0, 0,     			mBitmapIn.getWidth(), mBitmapIn.getHeight());     	for(int i = 0;i < mInPixels.length;i++) {     		float r = (float)(mInPixels[i] & 0xff);     		float g = (float)((mInPixels[i] >> 8) & 0xff);     		float b = (float)((mInPixels[i] >> 16) & 0xff);      		int mono = (int)(r * MonoMult[0] + g * MonoMult[1] + b * MonoMult[2]);      		mOutPixels[i] = mono + (mono << 8) + (mono << 16) + (mInPixels[i] & 0xff000000);     	}     	mBitmapOut.setPixels(mOutPixels, 0, mBitmapOut.getWidth(), 0, 0,     			mBitmapOut.getWidth(), mBitmapOut.getHeight()); } 

Что можно сказать? Простой цикл с независимыми итерациями, «перемалывающий» кучу пикселов. Посмотрим, как быстро он работает!
Для эксперимента возьмем МегаФон Mint на Intel® Atom™ Z2460 1.6GHz с Android ICS 4.0.4 и 600×1024 картинку с лего-роботом, несущим новогодние подарки.

image image

Замеры затраченного времени на обработку будем делать по следующей схеме:

private long startnow; private long endnow;  startnow = android.os.SystemClock.uptimeMillis(); Dalvik_MonoChromeFilter(); endnow = android.os.SystemClock.uptimeMillis(); Log.d("Timing", "Exеcution time: "+(endnow-startnow)+" ms"); 

Сообщение с тегом «Timing» можно получить с помощью ADB. Сделаем десяток замеров, перед каждым из которых сделаем перезагрузку устройства и убедимся, что разброс результатов измерений небольшой.
Время обработки изображения dalvik-реализацией составило 353 мсек.
Замечание: используя средства многопоточности (к примеру, класс AsyncTask для описания задач, выполняющихся в отдельных потоках), в лучшем случае можно выжать двухкратное ускорение, в силу наличия двух логических ядер на Intel Atom Z2460 1.6GHz.
Теперь рассмотрим renderscript-реализацию RS_MonoChromeFilter того же самого фильтра:

//mono.rs //or our small renderscript #pragma version(1) #pragma rs java_package_name(com.example.hellocompute)  //multipliers to convert a RGB colors to black and white const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};  void root(const uchar4 *v_in, uchar4 *v_out) {   //unpack a color to a float4   float4 f4 = rsUnpackColor8888(*v_in);   //take the dot product of the color and the multiplier   float3 mono = dot(f4.rgb, gMonoMult);   //repack the float to a color   *v_out = rsPackColorTo8888(mono); } 

    private RenderScript mRS;     private Allocation mInAllocation;     private Allocation mOutAllocation;     private ScriptC_mono mScript;     …     private void RS_MonoChromeFilter() {         mRS = RenderScript.create(this);/*создание Renderscript-контекста*/         mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,             Allocation.MipmapControl.MIPMAP_NONE,             Allocation.USAGE_SCRIPT);/*выделение и инициализация общей памяти для dalvik и renderscript контекстов */         mOutAllocation = Allocation.createTyped(mRS, mInAllocation.getType());         mScript = new ScriptC_mono(mRS, getResources(), R.raw.mono);/*создание и         привязка renderscript к renderscript-контексту */          mScript.forEach_root(mInAllocation, mOutAllocation);/*вызываем renderscript-функцию root c SMP параллелизмом в 2 потока */         mOutAllocation.copyTo(mBitmapOut);     }  

Замечание: производительность реализации будем оценивать как для dalvik.
Время обработки того же изображения renderscript-реализацией составило 112 мсек.
Получили выигрыш в производительности равный 3.2x (сравнение времени работы dalvik и renderscript: 353/112 = 3,2).
Замечание: время работы renderscript-реализации включает создание renderscript-контекста, выделение и инициализацию необходимой памяти, создание и привязку renderscript к контексту и работу функции root в mono.rs.
Замечание: Критичным местом для разработчиков мобильных приложений является размер получаемого apk файла. В этой реализации размер apk файла может увеличиться только на размер renderscript в байт-коде (*.bc файл) по сравнению с dalvik-реализацией. В моем случае размер dalvik-версии был равен 404KB, а размер renderscript-версии стал равен 406KB, из которых 2KB это renderscript байт-код (mono.bc).

3. Оптимизация renderscript

Текущую производительность renderscript можно повысить, отказавшись немного от точности арифметических операций с вещественными числами, что непринципиально для рассматриваемой задачи. Для этого в renderscript добавим прагму rs_fp_imprecise:

//mono.rs //or our small renderscript #pragma version(1) #pragma rs java_package_name(com.example.hellocompute) #pragma rs_fp_imprecise //multipliers to convert a RGB colors to black and white const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};  void root(const uchar4 *v_in, uchar4 *v_out) {   //unpack a color to a float4   float4 f4 = rsUnpackColor8888(*v_in);   //take the dot product of the color and the multiplier   float3 mono = dot(f4.rgb, gMonoMult);   //repack the float to a color   *v_out = rsPackColorTo8888(mono); } 

Как следствие этого, получаем дополнительный 10%ный прирост производительности у renderscript-реализации: 112 мсек. -> 99 мсек.
Замечание: в результате получаем визуально такое же монохромное изображение без каких-либо артефактов и искажений.
Замечание: У renderscript отсутствует механизм явного управления run-time компиляторной оптимизацией в отличие от NDK, т.к. компиляторные ключи предварительно прописаны внутри Android для каждой платформы (x86, ARM,…).

4. Зависимость времени работы dalvik и renderscript реализаций от размеров изображений

Исследуем следующий вопрос: какая зависимость времени работы каждой реализации от размера обрабатываемого изображения? Для этого возьмем 4 изображения размерами 300×512, 600×1024 (наше исходное изображение с лего-роботом), 1200×1024, 1200×2048 и сделаем соответствующие замеры времени монохромной обработки изображений. Результаты представлены ниже на графике и в таблице.

300×512 600×1024 1200×1024 1200×2048
dalvik 85 353 744 1411
renderscript 75 99 108 227
выигрыш 1.13 3.56 6.8 6.2

Заметим линейную зависимость времени для dalvik относительно размера изображения в отличие от renderscript. Это отличие можно объяснить наличием времени инициализации renderscript-контекста.
Для изображений сравнительно малых размеров выигрыш несущественный, т.к. время инициализации renderscript-контекста около 50-60 мсек. Однако на изображениях средних размеров, которые чаще всего используются на android-устройствах, выигрыш составляет 4-6x.

Заключение

В статье были рассмотрены dalvik и renderscript реализации монохромной обработки изображений разных размеров. За счет распараллеливания, компиляторной оптимизации и нативного исполнения кода renderscript солидно превосходит dalvik в производительности для изображений средних размеров. Этим небольшим примером я старался показать, когда renderscript может стать помощником повышения производительности приложений, которые при этом останутся аппаратно-независимыми.

ссылка на оригинал статьи http://habrahabr.ru/company/intel/blog/159699/


Комментарии

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

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