Pull to refresh
0

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

Reading time5 min
Views11K
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

Горизонтальные прямые на картинке в начале этого поста – параллельны. Хотя, возможно, что по отзывам наблюдателей окажется, что нет.
Tags:
Hubs:
+22
Comments24

Articles

Change theme settings

Information

Website
www.intel.ru
Registered
Founded
Employees
5,001–10,000 employees
Location
США
Representative
Анастасия Казантаева