Строим приложение из Array Building Blocks

Alexey Kryukov (Intel) (3 пост(а)) 05.09.2011 17:28

В этом выпуске: присматриваемся к новому продукту Intel® Array Building Blocks (Intel® ArBB), пишем ArBB приложение для подсчета суммы чисел в массиве, а также пытаемся оценить преимущества данного подхода и вызванную им головную боль.

Есть много решений, упрощающих разработку параллельных приложений. Один из первых стандартов в области параллельных технологий – Cilk, разработка которого началась в 1994 году в лаборатории Информатики M.I.T. Кстати, c 2009 года группа разоработчиков Cilk стала частью Intel. В 1997 году появилась первая версия другого решения – OpenMP. Сейчас это одна из наиболее распространенных технологий, ключевыми элементами которой являются конструкции для управления потоками и данными, библиотечные функции и переменные окружения. В 2006 году Intel выпустила Intel® Threading Building Blocks (Intel® TBB), где параллелизм реализован на уровне задач, а в распоряжение разработчиков предоставлены планировщик и потокобезопасные контейнеры. Продукт получился весьма успешным и используется как основа для других решений, в частности, ArBB, на котором остановимся подробнее.

Основная идея – прячем параллельный код по контейнерам.

Intel® ArBB представляет собой расширение C++ новыми классами и функциями, а также собственный runtime. Продукт появился в результате слияния своего предшественника Intel’s Ct Technology c технологией Rapidmind. Cуть ArBB в том, что программист пишет код, похожий на обычный, непараллельный, но использует типы данных, контейнеры и функции из ArBB (например, i32 вместо int, dense вместо vector и т.д.) и указывает, выполение каких функций должен взять на себя ArBB runtime. По умолчанию runtime сам определяет, сколько потоков создать, что каждый из них будет делать, как синхронизовать данные и т.д. Посмотрим как это выглядит на деле. Для этого разберем небольшой пример кода, в котором используется ArBB.

Hello ArBB! Как это выглядит на практике?

Одна из простых типовых задач – подсчет суммы элементов в массиве целых чисел. Код с использованием ArBB выглядит следующим образом.

#include <iostream>
#include <arbb.hpp>
// включение основного include файла ArBB

template <typename T>
void f(arbb::dense<T> arr, T& res)
// arr – исходный контейнер, в res – записывается результат
{
    res = arbb::add_reduce(arr);
    // использование встроенной ArBB функции
    // для подсчета суммы элементов
}

int main()
{
    int arr_size = 500;    // размер массива
    int* arr = (int*)arbb::aligned_malloc(sizeof(int)*arr_size);
    // выделение памяти под массив
    // использование arbb::aligned_malloc
    // гарантирует корректную работу ArBB с массивом
    for(int i = 0; i<arr_size;i++)  // инициализация массива
        arr[i]=i;
    arbb::dense<arbb::i32> arbb_arr;
    // декларируем контейнер ArBB
    arbb::bind(arbb_arr, arr, arr_size);
    // связываем исходный массив и контейнер ArBB
    arbb::i32 result;
    // объявляем переменную для записи результата
    arbb::call(f<arbb::i32>)(arbb_arr, result);
    // вызов ArBB runtime для выполнения функции f

    std::cout << arbb::value(result);
    // Доступ к ArBB скалярам осуществляется через arbb::value

    return 0;
}

В примере реализована функция f, принимающая два аргумента. Первый – исходный контейнер dense, что в терминах ArBB является аналогом vector. Cумму его элементов мы и будем считать. Второй аргумент нужен, чтобы вернуть результат.

Одна из «фишек» ArBB в том, что в продукте реализованы сотни полезных функций для всевозможных типовых операций над разными наборами данных. Это сильно облегчает жизнь: во-первых, не надо заботиться о реализации того или иного алгоритма, а во-вторых не надо городить много вложенных циклов с зависящими друг от друга параметрами, в результате код становится более читаемым. Одна из таких встроенных в ArBB функций – add_reduce, возвращает сумму элементов в контейнере.

В main() создается и инициализируется массив, объявляется ArBB контейнер, и происходит связывание массива и контейнера. Зачем все это? В использовании ArBB есть нюанс: ArBB может производить вычисления только в своем пространстве и только с ArBB типами (нельзя передать C++ массив напрямую в f). Теперь же массив и ArBB контейнер содержат одни и те же данные. Далее объявляем ArBB переменную для записи результата и вызываем функцию f. arbb::call(имя)(аргументы) – это и есть вызов ArBB runtime с указанием выполнить функцию, исполнение происходит в ArBB пространстве. Осталось вывести результат. Единственное, что надо не забыть – это прописать зависимость от библиотеки ArBB в свойствах проекта или напрямую в командной строке при компиляции, например

icl /D WIN32 /D NDEBUG /EHsc application.cpp /link arbb.lib

Что имеем в результате: минусы

  • Написание и разбор ArBB кода может показаться утомительным, особенно с непривычки. Разработку осложняют требования использовать специальные типы данных. Необходимо организовать отдельное пространство для ArBB вычислений, а также связывать контейнеры из C++ и ArBB.
  • Собственный runtime приносит дополнительные накладные расходы.

Что имеем в результате: плюсы

  • Гарантированное отсутствие data races & deadlocks.
  • Высокоуровневый API: сотни операций с контейнерами, в том числе и многомерными, делаются в одну строчку посредством встроенных функций, не загромождая код и мозг ненужными деталями.
  • Собственный runtime обеспечивает отличную переносимость приложений. Не надо ничего изменять, чтобы приложение оптимально работало и на multi-, и на manycore системах, будь то 4-х ядерный десктоп, 16-core двухсокетный сервер или 32-ядерная MIC карта. Также нет необходимости оптимизировать приложение под конкретный набор SIMD инструкций. Это большое преимущество как с точки зрения цены поддержки приложения, так и в случае если вы не знаете заранее, на каком железе оно будет запускаться.

Лучшее место для начала знакомства с ArBB, пожалуй, здесь. Продукт сейчас в Beta стадии.

Категории: Intel Software Network, Параллельное программирование

Пожалуйста, обратитесь к странице Уведомление об оптимизации для более подробной информации относительно производительности и оптимизации в программных продуктах компании Intel.

Комментарии (10)

05.09.2011 07:35

Dmitry Oganezov (Intel)
Dmitry Oganezov (Intel)Всего баллов:
25,608
Community Manager
Welcome, Алексей! Добро пожаловать в наш скромный блог! :)

Кстати меня несколько удивил тот факт, что Cilk-то, оказывается, старше OpenMP! Не поленился, схолил в википедию - и действительно, старше! Кто бы мог подумать...

С нетерпением ждем продолжения - особенности реализации ArBB runtime, в частности, рассказ о загадочной "двухфазной" компиляции ;) - имхо именно в этом главная фишка!
05.09.2011 07:48

Dmitry Kozlov (Intel)
Dmitry Kozlov (Intel)Всего баллов:
715
коричневый пояс
несколько неожиданно выглядят две вещи:
1. сначала строчка кода, а потом комментарий что она делает
2. а нельзя без arbb::call'а позвать arbb::add_reduce?
05.09.2011 08:19

Dmitry Oganezov (Intel)
Dmitry Oganezov (Intel)Всего баллов:
25,608
Community Manager
Хм, а разве так выглядит лучше?

// а сейчас мы попробуем вызвать фунцию my_function
my_function();

Хотя ты прав, комментарии - зло.
05.09.2011 08:21

Alexey Kryukov (Intel)
Alexey Kryukov (Intel)Всего баллов:
510
коричневый пояс
1. сначала строчка кода, а потом комментарий что она делает
Просто хотел, чтобы вширь скролл-бар не надо было крутить. Может переборщил малость :)
2. а нельзя без arbb::call'а позвать arbb::add_reduce?
Можно. С arbb::add_reduce это прокатит. Но разработчики продукта рекомендуют использовать call. Насколько мне известно, причины следующие: нет гарантии что arbb runtime будет корректно вызываться из произвольных операций с любыми ArBB типами. И есть еще момент: если 10 arbb операций поместить последовательно в main, то arbb runtmie будет подниматься 10 раз, и столько же раз будем возвращаться в C++ space. А если все делать из-под arbb::call, то будет только по одному переходу. Соответственно, ниже накладные расходы.
06.09.2011 00:12

ilnarb
ilnarbВсего баллов:
5,804
коричневый пояс
не очень понял для чего городить такую конструкцию, неужели нельзя массив сразу на нужное число памяти инициализировать, как вектор?
    int arr_size = 500;    // размер массива   
    int* arr = (int*)arbb::aligned_malloc(sizeof(int)*arr_size);   18.    // выделение памяти под массив   
    // использование arbb::aligned_malloc   20.    // гарантирует корректную работу ArBB с массивом   
    for(int i = 0; i<arr_size;i++)  // инициализация массива   22.        arr[i]=i;   
    arbb::dense<arbb::i32> arbb_arr;   24.    // декларируем контейнер ArBB   
    arbb::bind(arbb_arr, arr, arr_size);   26.    // связываем исходный массив и контейнер ArBB  
06.09.2011 00:16

ilnarb
ilnarbВсего баллов:
5,804
коричневый пояс
честно говоря, ограничения выглядят лишними:
- инициализация массива длинным путем
- а есть ли там lambda выражения?

TBB выглядит намного проще, не говоря о OpenMP, там все массивные вычисления проще записать.
Одно радует, оптимизацией базовых операций на SIMD, AVX, .. займутся разработчики ArBB
06.09.2011 03:44

Alexey Kryukov (Intel)
Alexey Kryukov (Intel)Всего баллов:
510
коричневый пояс
неужели нельзя массив сразу на нужное число памяти инициализировать, как вектор?
Можно :) Но работать это будет гораздо медленнее. Почему? Пока еще не сам разобрался. Постараюсь осветить это в следующем посте, который, наверняка будет об arbb runtime
06.09.2011 05:59

ilnarb
ilnarbВсего баллов:
5,804
коричневый пояс
Alexey Kryukov (Intel)
он в каком виде распространяется? исходники есть? совсем ломает заполнять большущую форму для beta survey
06.09.2011 06:15

Alexey Kryukov (Intel)
Alexey Kryukov (Intel)Всего баллов:
510
коричневый пояс
ilnarb
Сейчас у arbb Бета программа. Я так понимаю, для участия в ней survey надо будет все таки заполнять.
arbb не open source, для установки нужен серийник или лицензия.
Кстати. Судя по информации на страничке Composer XE
http://software.intel.com/en-us/articles/intel-composer-xe/ arbb
через некоторое время arbb будет поставляться вместе с ним.
22.09.2011 05:15

Alexey Kryukov (Intel)
Alexey Kryukov (Intel)Всего баллов:
510
коричневый пояс
Есть продолжение
http://software.intel.com/ru-ru/blogs/2011/09/22/array-building-blocks-2/

Обратная ссылка (0)


Оставить комментарий  

Для получения технической помощи посетите сайт службы поддержки.
Имя (обязательно)*

Электронная почта (обязательно; не будет отображено на этой странице)*

Ваш URL-адрес (необязательно)


Комментарий*