1 сентября 2011 в 10:52

ArBB, Cilk+, OpenMP, OpenCL, TBB — День Знаний или День Выборов

Parallel
Вспомните, делали ли вы в последние годы какой-нибудь существенный выбор, не почитав предварительно в интернете отзывов тех, кто уже выбрал это ранее?

Мы живем в эпоху «развивающегося отзывизма».
Почти все покупки, выбор места отдыха, работы, ученья и леченья, банка и танка, фильма и фирмы… Лучше прочесть один отзыв, чем тысячи реклам.

Хотя, скорее всего, отзывами вы пользовались не во всех случаях.
Например, при выборе спутника\спутницы жизни.
Или при выборе кабинки в общественном туалете :).
Или – при выборе способа распараллеливания программ. В последнем случае — наверное, просто потому, что таких отзывов вам не попадалось. Попробую это исправить. А именно, расскажу, чего ждать от Cilk+, OpenMP, OpenCL, TBB и ArBB(Ct) с точки зрения их возможностей, простоты освоения и использования, качества документации, а также ожидаемой производительности.

Сразу отмечу, что все нижеописанные средства либо бесплатны, либо входят в цену компилятора.

OpenMP.


Набор прагм компилятора для автоматического распараллеливания (также можно использовать дополнительные библиотечные функции).
Поддерживается всеми основными компиляторами, иначе — просто игнорируется, не вызывая ошибок.
Работает на всех распространенных архитектурах (в теории – и на ARM) и ОС (в теории – даже на Android).

Документация хорошая и есть везде — вплоть до глянцевых журналов.

Простота изучения — исключительная. Время освоения и имплементации – минуты. Для сложного проекта – не более часа.

Отладка – ограничена, но возможна – см. Intel Parallel Studio.

Недостатки: не использует GPU, не поддерживает многие нужные для «продвинутого» контроля и синхронизации потоков функции; не всегда обеспечивает хорошую производительность; неоптимально «комбинируется» в различных компонентах приложения и с другими средствами распараллеливания.

Пример. Цикл for с использованием OpenMP будет выглядеть так:
#pragma omp parallel for
for (i = 0; i < n; ++i) 
     result[i] = a[i] * b[i];



OpenCL(Open Computing Language)


Молодой (2008г рождения) стандарт гетерогенного параллельного программирования. То есть, внутри использует не только CPU, но и GPU, что является его главным, а может, и единственным преимуществом. Поддерживается AMD, Apple, ARM, Intel, NVidia и всеми компаниями-производителями мобильных телефонов. Не поддерживается Microsoft.
Еще одно декларируемое достоинство OpenCL – автоматическая векторизация кода при наличии возможностей железа. Но того же эффекта можно добиться и не используя OpenCL :)

Концепция стандарта: центральный хост и множество OpenCL устройств (Compute Unit), параллельно выполняющих определенные программистом функции-ядра (kernel). Кернелы пишутся на диалекте языка С (С с некоторыми ограничениями и дополнениями) и компилируются специальным компилятором.
Основная программа, выполняемая на хосте, должна много всего и всем :):
  • создать окружение OpenCL,
  • создать кернелы,
  • определить платформу выполнения = контексты, устройства и очереди,
  • создать и построить программу (динамическую библиотеку для кернелов),
  • выделить и инициализировать объекты в памяти,
  • определить ядра и присоединить их к их аргументам, и, наконец, передать память и ядра на выполнение OpenCL устройствам.

Документация: очень мало.
Самое сложное в изучении\имплементировании средство, особенно учитывая недостаток документации и, особенно, примеров. Время освоения и имплементации – дни. Для сложного проекта – недели.

Прочие недостатки: не лучшая производительность на имеющихся примерах, использующих только CPU, трудности отладки и поиска проблем с производительностью.

Пример. Цикл for из функции
void scalar_mul(int n, const float *a, const float *b, float *result) { 
   int i; 
   for (i = 0; i < n; ++i) 
       result[i] = a[i] * b[i];
 } 


в переводе на OpenCL превратиться в кернел:
__kernel void scalar_mul(__global const float *a, __global const float *b, 
__global float *result) { 
         size_t id = get_global_id(0); 
          result[id] = a[id] * b[id]; 
}


… плюс понадобится еще полный экран кода (!) для основной программы-хоста (см. выше). Этот код, вызывающий специальные OpenCL функции, конечно, можно списать из примера Intel OpenCL SDK, но разбираться в нем все равно придется.



Три следующие средства распараллеливания программ образуют Inel Parallel Building Blocks:
Cilk Plus, TBB, ArBB.

Cilk Plus.

«Плюс» означает расширения Cilk для работы с массивами.
Расширение С\С++, поддерживаемое исключительно компиляторами Intel (Windows, Linux) и, с августа 2011, — gcc 4.7, что сразу показывает недостаток – отсутствие реальной кросс-платформености. GPU также не поддерживается.

Достоинства:
Простота освоения. Cilk немногим сложнее OpenMP. Вводится в проект за считанные минуты, в худшем случае – часы работы.
При этом, производительность превосходит OpenMP. Кроме того, Сilk хорошо комбинируется со всеми Inel Parallel Building Blocks и OpenCL.
При использовании Intel Cilk SDK изменения кода минимальны, всю работу выполняет компилятор «за сценой».

Документация: немного, но, учитывая простоту Cilk, это не проблема.

Пример. Ваш любимый цикл for на Cilk будет выглядеть так:
cilk_for (i = 0; i < n; ++i) {
      result[i] = a[i] * b[i];
 } 


TBB (Threading Building Blocks)


Созданная Intel библиотека С++ темплейтов для параллельного программирования. Работает на Linux, Windows, Mac и даже на Xbox360, не требует компилятора Intel. Недостаток: не использует GPU.
В библиотеке реализованы:
• потокобезопасные контейнеры: вектор, очередь, хеш-таблица;
• параллельные алгоритмы for, reduce, scan, pipeline, sort и тд.
• масштабируемые распределители памяти;
• мьютексы и атомарные операции;

Документация и примеры: много, хорошего качества.

Простота освоения и использования. Для не имеющих опыта пользования шаблонами в коде – достаточно сложно. Для имеющих — тоже не всегда элементарно. Могут потребоваться значительные изменения кода. Время изучения\имплементации — от одного рабочего дня до недели.

Достоинства: отличная производительность, независимость от компилятора, возможность использовать отдельные компоненты библиотеки независимо.

Пример.
 void scalar_mul(int n, const float *a, const float *b, float *result) { 
       for (int i = 0; i < n; ++i) 
            result[i] = a[i] * b[i];
 } 

с использованием ТВВ придется превратить в оператор() класса так называемого Body (тела цикла):

using namespace tbb;
class ApplyMul {
     public:
     void operator()( const blocked_range<size_t>& r ) const {
           float *a = my_a;
           float *b = my_b;
           float *result = my_result;

          for( size_t i=r.begin(); i!=r.end(); ++i )
            result[i] = a[i] * b[i];
      }
      ApplyMul( float a[],  float b[], float result []) :
      my_a(a), my_b(b), my_result(result)
      {}
};


Где blocked_range -темплейт-итератор, предоставляемый tbb.

И только после этого можно использовать tbb parallel_for
void parallel_mul ( float a[], float b[],float result[], int n ) {
     parallel_for(blocked_range<size_t>(0,n), ApplyMul(a, b, result));
}


ArBB (Array Building Blocks).


В девичестве – Ct, про который уже писал в этом блоге izard. Intel библиотека С++ шаблонов для параллельного программирования.
Intel ArBB работает на Windows* и Linux*, поддерживается компиляторами Intel, Microsoft Visual C++ и GCC. При наличии соответствующего run-nime должен работать на GPU и грядущей Intel MIC

Достоинства: заложенная в дизайн полная поточная безопасность (отсутвие data race) использует внутри себя TBB, соответственно, хорошо комбинируется в разных модулях.

Документация: увы, немногословна, примеры – вполне нормальны.

Трудность освоения\имплементации – на уровне TBB.

Недостатки:
Все еще находится в стадии beta.
Спроектирован для обработки больших массивов данных, на небольших массивах за счет накладных расходов не обеспечивает хорошей производительности.
Пример:
Во что превратиться пресловутый цикл for в ArBB? При первом взгляде в документацию можно подумать, что в _for. Но нет. _for в ArBB – это как раз указание на то, что цикл имеет зависимости в итерациях и может выполняться только последовательно. «parallel for» в ArBB вообще нет.
А все тот же
 void scalar_mul(int n, const float *a, const float *b, float *result) { 
       for (int i = 0; i < n; ++i) 
            result[i] = a[i] * b[i];
 } 


превратится в
void parallel_mul(dense<f32> a, dense<f32> b, dense<f32> &result) { 
    result = a * b; 
} 


с вызовом
dense<f32> va; bind (va, a, n);
dense<f32> vb; bind (vb, b, n);
dense<f32> vres; bind (vres, result, n);

call(parallel_mul)(va, vb, vres);


Резюме №1
Сводная таблица выбора.image

Резюме №2

Горизонтальные прямые на картинке в начале этого поста – параллельны. Хотя, возможно, что по отзывам наблюдателей окажется, что нет.
+22
6946
24
vikky13 122,3

комментарии (24)

0
ZlodeiBaal, #
1)А CUDA??? Или вы только по тому что поддерживает проц проходились?
2) Почему OpenCL без GPU не обеспечивает производительности? Тут были где-то тесты на хабре, сравнивали с OpenMP. Там были одинаковые производительности показаны.
3) «Страница кода для запуска OpenCL» — ну, если использовать соответствующие обёртки — всего пара строчек)

А так в целом понравилось. Про последние три знал очень мало — почитал теперь)
+3
vikky13, #
1) Вы угадали, CPU должен участвовать, за остальным — в блоги к производителям GPU :)
2)Почему не обеспечивает — вопрос сложный, это много от чего зависит. Короткий ответ — накладные расходы. И, правильно, да OpenMP — я же говорю, что и она не обеспечивает :)
3) Смотрела Intel OpenCL SDK (что ж еще? :) ) и оберток не заметила. Если они есть — отлично.
+1
ZlodeiBaal, #
Не знаю… Про производительность это сложный вопрос. На CL есть высокий доступ к вычислительному устройству (в том числе синхронизации различные). При наличие прямых рук производительность там будет не хуже чем на любой другой система использующей процессор. Но мороки будет много.

Обёртки это обычно открытые проекты. Вот тут про некоторые из них написано немного — habrahabr.ru/blogs/hi/124873/
Без них CL ещё более сложен и уныл)
+1
vikky13, #
>> Но мороки будет много.
Вот это я и имела в виду. Не факт, что стоит возиться. Я совсем не против OpenCL, но надо быть объективным.

Спасибо за отличный комментарий.
0
ZlodeiBaal, #
Спасибо за хорошую статью)
0
DmitryO, #
Если долго и внимательно смотреть на картинку в начале поста, то она превратится в картинку из этого поста :) — это так и задумано? :)

Отличный обзорный пост! Но его надо продолжить. Тут прозвучала оценка технологий с точки зрения простоты изучения и доступности материалов. Хотелось бы также услышать рекомендации по выбору технологии в зависимости от типов (объемов, сложности, и т.п.) решаемых задач.

0
vikky13, #
Оох… у меня нет времени долго смотреть на картинки :) так что — не знаю.

я знала, что кто-нибудь это обязательно попросит :) Но это проще попросить, чем сделать. Буду думать.
0
DmitryO, #
Так это же логично! К примеру, ArBB, судя по твоей замечательной табличке, проигрывает практически всем. Возникает резонный вопрос: зачем-то же его все-таки сделали? Миллионы менеджеров Intel не могут ошибаться! (С)
+2
vikky13, #
:)
ArBB — это монстр :), соответственно, ему нужны тяжелые монстровые задачи.
0
KindDragon, #
Почему для Clock Plus и TBB нету отдельного жирного подпункта «недостатки» как у остальных, а они упомянуты в тексте? И насколько я понимаю недостаток что не используется GPU относится и к Click Plus, хотя не упомянут в тексте.
0
vikky13, #
спасибо, это не по злому умыслу, а по недосмотру.
Сейчас поправлю.
Но отдельным пунктом недостатки тут выносить не хочется — они уместны в тексте, прсто выделю жирным и добавлю.
Вы вот тоже опечатались clock вместо cilk написали :)
0
KindDragon, #
> Вы вот тоже опечатались clock вместо cilk написали :)
Черт :-)
0
Robotex, #
Мне интересно возможность выбора технологий. Т.е. при запуске приложение получает конфигурацию оборудования, а затем определяет: если карта от NVidia — то CUDA, ATI — ATI Stream, Intel — OpenCL, карта не поддерживает — OpenMP, иначе последовательное приложения. Возможно такое реализовать?
+1
vikky13, #
Если мы говорим про работу на CPU, то там все просто. В основе всех библиотек — нативный интерфейс работы с потоками ОС, так что в принципе все библиотеки распараллеливания на CPU «взаимозаменяемы» — то есть, теоретически возможно взять интерфес одной и звать внутри начинку от другой. Но интерфейс каждой из них заточен под внутреннюю структуру (или наоборот:) — то есть, вышеупомянутая штука будет немного медленнее или сильно медленнее, чем это возможно (при вызове быстрейшей библиотеки).
Если же включить сюда и GPU, то нам нужны: код для CPU, специально скомпилированный особым компилятором код для конкретного GPU плюс блок, загружающий этот код на GPU и обрабатывающий потом результаты. Как это можно сделать автоматически, да еще и в рантайме из одного исходного кода, не зная, что куда — я не представляю.
0
Robotex, #
А если сделать распараллеливаемые функции в динамических библиотеках и загружать нужную библиотеку на лету?
0
vikky13, #
Ну кто-то же должен обернуть, например, каждую итерацию цикла в функцию, потом куда-то ее вынести и скомпилировать отдельной библиотекой, потом надо решить проблему передачи данных туда — выделить для этого память, потом… короче, В итоге мы придем к OpenCL :)
0
stmuxa, #
«Страница кода для запуска OpenCL» — это самая вершина айсберга.
Внутри все намного сложнее, зато и возможностей где можно развернуться очень много.
(Сейчас пишу именно на OpenCL'е)
(Выше имелась в виду GPU часть OpenCL'я)
+1
ilya314, #
Для полноты картины еще две технологии:

PPL (Parallel Patterns Library)
Это аналог OpenMP от Microsoft, реализован в виде библиотеки средствами языка C++11 (lambda-выражения передаются параметрами функций). Весьма вероятно, что спецификации открыты, но учитывая недостаточную распространенность C++11 и существование OpenMP это дело возможно есть только в vs2010.

Намного более интересна другая вещь — C++ Accelerated Massive Parallelism (C++ AMP). Это замена OpenCL, но с использованием C++, как и PPL — это просто библиотека, которая работает в рамках языка C++11. Это дело недавно демонстрировали в работе, синтаксис немного показали, будет доступно в следующей версии Visual Studio. Важно, что спецификация будет точно открытой.
Некоторые ссылки:
C++ Accelerated Massive Parallelism




0
vikky13, #
Спасибо, интересно. А самое интересное — это как AMP по производительности сравнительно с OpenCL.
0
ilya314, #
Это конечно интересно посмотреть, но реально можно будет сравнить, когда до пользователей дойдет этот инструмент. А вообще рекомендую видео с Herb Sutter — там демонстрируется работа моделирования частиц, GFlops-ы на экран выводятся и на разном железе показано как это все работает, какое ускорение.
0
ilya314, #
Дополнение по поводу c++ amp, случайно запостил недописанный комментарий. Ссылки:
C++ Accelerated Massive Parallelism
Microsoft brings GPU computing to C++ with C++ AMP (есть слайды)

На channel9 можно еще видео по С++ AMP найти.
0
ilya314, #
Доклад (видео) по C++ AMP с демонстрацией приложения:

Herb Sutter: Heterogeneous Computing and C++ AMP
0
beeruser, #
ISPC — вот это вещь. От того же интела, как ни странно.
ispc.github.com/
0
vikky13, #
Спасибо! Я про такое не знала — Интел велик во всех смыслах :)
А это вы в теории им восхищаетесь или на практике? От этого много чего зависит :)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.