Quantcast
Channel: Статьи Intel Developer Zone
Viewing all articles
Browse latest Browse all 357

Неоднородные рабочие группы OpenCL™ 2.0

$
0
0

Download PDF
Download Zipfile

Содержание

Содержание
Введение
Неоднородные рабочие группы
Обзор учебной программы
Требования для учебной программы
Запуск учебной программы
Справочные материалы

Введение

Модель выполнения OpenCL™ включает понятие рабочих групп, которые являются группами отдельных рабочих элементов в NDRange. Рабочие элементы в составе одной и той же рабочей группы могут вместе использовать локальную память, проводить синхронизацию с помощью барьера группы и взаимодействовать с помощью таких групповых функций, как async_work_group_copy. Если приложение использует OpenCL 1.x, то размеры NDRange должны нацело (без остатка) делиться на размеры рабочих групп. Если вызов clEnqueueNDRangeKernelвключает параметры global_sizeи local_sizeкоторые не делятся нацело, вызов возвратит код ошибки CL_INVALID_WORK_GROUP_SIZE. Если же вызов clEnqueueNDRangeKernelуказывает значение NULL для параметра local_size, разрешая выполняемому модулю выбрать размер рабочей группы, то выполняемому модулю потребуется выбрать размер, на который можно нацело разделить глобальные размеры NDRange.

Необходимость выбора такого размера рабочих групп, чтобы на него нацело делился размер NDRange, может вызвать затруднение у разработчиков. Рассмотрим простой алгоритм размытия изображения 3х3 (алгоритм входит в учебный код). В этом алгоритме каждый выходной пиксель вычисляется как среднее значение для значений входных пикселей в соседней области размером 3х3. Такие алгоритмы применяются во множестве приложений для обработки изображений, работающих с соседними группами пикселей, для таких операций, как свертывание, стирание, размытие и фильтрация по среднему. В алгоритмах такого типа можно использовать разные способы для обработки выходных пикселей, расположенных на рамке изображения. Эти пиксели зависят от пикселей вне границ входного изображения. Эта проблема показана на приведенном ниже рисунке.

Можно обрабатывать пиксели границы различными способами, например принять постоянное значение границы или повторно использовать соседние пиксели границы. Но для этого требуется применять попиксельную обработку внутри ядра, что вызовет излишнюю нагрузку. В некоторых приложениях входные значения рамок не имеют значения, их можно пропустить. В этом случае размер NDRange совпадает с размером выходного изображения за вычетом области рамки. При этом зачастую получается размер NDRange, который трудно нацело разделить. Например, для применения фильтра 3x3 к изображению 1920x1080 требуется рамка толщиной в один пиксель с каждой стороны. Проще всего это сделать с помощью ядра 1918х1078. Но ни 1918, ни 1078 не делятся нацело на значения, дающие рабочие группы оптимального размера.

В этом примере используется размытие 3х3, но эта проблема существует и для других алгоритмов.

Неоднородные рабочие группы

В OpenCL 2.0 появилась новая возможность, в которой устранены проблемы, описанные в предыдущем разделе. Речь идет о так называемых неоднородных рабочих группах: выполняемый модуль OpenCL 2.0 может разделить NDRange на рабочие группы неоднородного размера по любому измерению. Если разработчик укажет размер рабочей группы, на который размер NDRange не делится нацело, выполняемый модуль разделит NDRange таким образом, чтобы создать как можно больше рабочих групп с указанным размером, а остальные рабочие группы будут иметь другой размер. Например, для NDRange размером 1918x1078 рабочих элементов при размере рабочей группы 16x16 элементов среда выполнения OpenCL 2.0 разделит NDRange, как показано на приведенном ниже рисунке.

Благодаря этому OpenCL может использовать рабочие группы любого размера для любого размера NDRange, когда разработчик передает значение NULL параметра local_sizeв clEnqueueNDRangeKernel. В целом использование значения NULL в параметре local_sizeостается предпочитаемым методом выполнения ядер, если логика вашего приложения не требует какого-либо определенного размера рабочей группы.

Внутри кода ядра встроенная функция get_local_size()возвращает фактический размер рабочей группы, из которой она была вызвана. Если ядру требуется точный размер, указанный для параметра local_sizeв clEnqueueNDRangeKernel, то встроенная функция get_enqueued_local_size() возвращает эти значения.

Чтобы включить использование неоднородных рабочих групп, необходимо скомпилировать ядро с флагом “-cl-std=CL2.0”, включающим эту и другие возможности OpenCL 2.0. Без использования этого флага компилятор будет использовать версию OpenCL 1.2, даже если устройство поддерживает OpenCL 2.0. Кроме того, неоднородные рабочие группы можно отключить для ядер, скомпилированных для флага “-cl-std=CL2.0” с помощью флага “-cl-uniform-work-group-size”. Это может быть полезно для устаревшего кода ядра до полного перехода на OpenCL 2.0.

Функция неоднородных рабочих групп в OpenCL 2.0 повышает простоту использования OpenCL и может повысить производительность некоторых ядер. Разработчики больше не добавляют код системы и ядра для работы с размерами NDRange, которые не делятся нацело. Код, созданный для использования этой возможности, может эффективно использовать SIMD и выравнивание доступа к памяти: такие преимущества обеспечиваются правильным выбором размера рабочих групп.

Обзор учебной программы

TВ коде учебной программы реализован алгоритм размытия 3х3, описанный выше. Самая интересная часть кода находится в файле main.cpp. Код в этом файле действует следующим образом:

  1. Загрузка входного растрового файла.
  2. Сборка ядра OpenCL C с помощью параметров OpenCL 1.2.
    // Get the box blur kernel compiled using OpenCL 1.2 (which is the
    // default compilation, even on an OpenCL 2.0 device).  This allows
    // the code to show the pre-OpenCL 2.0 behavior.
    cl::Kernel kernel_1_2 = GetKernel(device, context);
  3. Сборка ядра OpenCL C с помощью параметров OpenCL 2.0 (обратите внимание на передачу параметров сборки с флагом OpenCL 2.0).
    // Get the box blur kernel compiled using OpenCL 2.0.  OpenCL 2.0
    // is required in order to use the non-uniform work-groups feature.
    kernel_2_0 = GetKernel(device, context, "-cl-std=CL2.0");
  4. Задание глобального размера, который используется для всех разновидностей запущенных ядер.
    // Set the size of the global NDRange, to be used in all NDRange cases.
    // Since this is a box blur, we use a global size that is two elements
    // smaller in each dimension.  This creates a range which often doesn't
    // divide nicely by local work sizes we might commonly pick for running
    // kernels.
    cl::NDRange global_size = cl::NDRange(input.get_width() - 2,
                                          input.get_height() - 2);
  5. Размытие изображения с помощью версии ядра, скомпилированной для OpenCL 1.2, параметр local_sizeимеет значение NULL.
    // Blur the image with a NULL local range using the OpenCL 1.2 compiled
    // kernel.
    cout << "Compiled with OpenCL 1.2 and using a NULL local size:"<< endl << endl;
    output = RunBlurKernel(context, queue, kernel_1_2, global_size,
                           cl::NullRange, input, true);
  6. Размытие изображения с помощью версии ядра, скомпилированной для OpenCL 1.2, при значении параметра local_size 16x16.
    // Blur the image with an even local range using the OpenCL 1.2
    // compiled kernel.  This won't work, even if we are running on an
    // OpenCL 2.0 implementation.  The kernel has to be explicitly compiled
    // with OpenCL 2.0 compilation enabled in the compiler switches.
    try
    {
        cout << "Compiled with OpenCL 1.2 and using an even local size:"<< endl << endl;
        output = RunBlurKernel(context, queue, kernel_1_2,
                               global_size, cl::NDRange(16, 16), input,
                               true);
        cout << endl;
        output.Write(output_files[1]);
    }
    catch (...)
    {
        cout << "Trying to launch a non-uniform workgroup with a kernel ""compiled using"<< endl <<"OpenCL 1.2 failed (as expected.)"<< endl << endl;
    }
  7. Размытие изображения с помощью версии ядра, скомпилированной для OpenCL 2.0, при значении параметра local_size NULL.
    // Blur the image with a NULL local range using the OpenCL 2.0
    // compiled kernel.
    cout << "Compiled with OpenCL 2.0 and using a NULL local size:"<< endl << endl;
    output = RunBlurKernel(context, queue, kernel_2_0, global_size,
                           cl::NullRange, input, true);
  8. Размытие изображения с помощью версии ядра, скомпилированной для OpenCL 2.0, при значении параметра local_size 16x16.
    // Blur the image with an even local range using the OpenCL 2.0
    // compiled kernel.  This will only work on an OpenCL 2.0 device
    // and compiler.
    cout << "Compiled with OpenCL 2.0 and using an even local size:"<< endl << endl;
    output = RunBlurKernel(context, queue, kernel_2_0,
                           global_size, cl::NDRange(16, 16), input,
                           true);
  9. Запись выходных файлов, созданных в пп. 2—5.

Для каждого варианта в пп. 5—8 результаты вызова get_local_size () и get_get_enqueued_local_size () в каждом из четырех углов NDRange отображаются на экране. Таким образом, мы видим, как происходит разделение NDRange на рабочие группы.

Для предоставленного входного изображения шаг 6 не будет выполнен, поскольку NDRange невозможно разделить без остатка на рабочие группы 16х16. Кроме того, шаги 7 и 8 не будут выполнены для реализаций OpenCL, не поддерживающих OpenCL 2.0.

Ядро, реализующее алгоритм размытия, хранится в BoxBlur.cl. Оно содержит очень простую реализацию, но не является наиболее эффективным способом применения размытия.

Требования для учебной программы

Для сборки и запуска этой учебной программы нужен ПК, соответствующий следующим требованиям:

  • Процессор серии Intel® Core™ с кодовым названием Broadwell
  • Microsoft Windows* 8 или 8.1
  • Intel® SDK для приложений OpenCL™ версии 2014 R2 или более поздней
  • Microsoft Visual Studio* 2012 или более поздней версии

Запуск учебной программы

Учебная программа представляет собой консольное приложение, которое прочитывает входное растровое изображение и записывает выходные растровые изображения для каждой разновидности NDRange, описанной в приведенном выше разделе (кроме шага 3, поскольку в этом случае возникает ошибка). Эта учебная программа поддерживает несколько параметров командной строки:

ПараметрОписание
-h, -?Отображение текста справки и выход.
-i <входной префикс>Префикс (имя файла) входного растрового изображения. Полное имя файла будет выглядеть так: <входной префикс>.bmp. Этот файл должен быть 24-битным растровым изображением.
-o <выходной префикс>Префикс выходного растрового изображения. Имена создаваемых файлов будут выглядеть так: <выходной префикс>_N.bmp, где N — число от 0 до 3..

 

После запуска учебной программы для предоставленного рисунка результат будет таким:

Input file: input.bmp
Output files: output_0.bmp, output_1.bmp, output_2.bmp, output_3.bmp

Device: Intel(R) HD Graphics 5500
Vendor: Intel(R) Corporation

Compiled with OpenCL 1.2 and using a NULL local size:

   Work Item  get_global_id()  get_local_size()  get_enqueued_local_size()
---------------------------------------------------------------------------
    Top left       (  0,   0)        (  1, 239)                  undefined
   Top right       (637,   0)        (  1, 239)                  undefined
 Bottom left       (  0, 477)        (  1, 239)                  undefined
Bottom right       (637, 477)        (  1, 239)                  undefined


Compiled with OpenCL 1.2 and using an even local size:

Trying to launch a non-uniform workgroup with a kernel compiled using
OpenCL 1.2 failed (as expected.)

Compiled with OpenCL 2.0 and using a NULL local size:

   Work Item  get_global_id()  get_local_size()  get_enqueued_local_size()
---------------------------------------------------------------------------
    Top left       (  0,   0)        (  1, 239)                 (  1, 239)
   Top right       (637,   0)        (  1, 239)                 (  1, 239)
 Bottom left       (  0, 477)        (  1, 239)                 (  1, 239)
Bottom right       (637, 477)        (  1, 239)                 (  1, 239)


Compiled with OpenCL 2.0 and using an even local size:

   Work Item  get_global_id()  get_local_size()  get_enqueued_local_size()
---------------------------------------------------------------------------
    Top left       (  0,   0)        ( 16,  16)                 ( 16,  16)
   Top right       (637,   0)        ( 14,  16)                 ( 16,  16)
 Bottom left       (  0, 477)        ( 16,  14)                 ( 16,  16)
Bottom right       (637, 477)        ( 14,  14)                 ( 16,  16)


Done!

Входное изображение имеет размер 640x480, поэтому размер NDRange в каждом случае составит 638x478. Приведенный выше результат показывает, что запуск ядра OpenCL 1.2 со значением NULL параметра local_sizeвынуждает использовать нечетные размеры для каждой рабочей группы (1, 239). Размеры рабочих групп, не являющиеся степенями двойки, могут работать очень медленно в некоторых ядрах. Конвейеры SIMD могут простаивать, синхронный доступ к памяти может нарушиться.

Запуск ядра OpenCL 1.2 с указанным размером рабочей группы (16x16) выдает ошибку, поскольку ни 648, ни 478 не делятся нацело на 16.

Запуск ядра OpenCL 2.0 со значением NULL параметра local_sizeпозволяет выполняемому модулю OpenCL разделить NDRange на рабочие группы любого размера. Выше показан результат: видно, что выполняемый модуль продолжает использовать однородный размер рабочих групп точно так же, как для ядра OpenCL 1.

Запуск ядра OpenCL 2.0 с заданным размером рабочей группы (16x16) приведет к тому, что размер NDRange будет разделен на неоднородные рабочие группы. Мы видим, что левая верхняя рабочая группа имеет размер 16х16, правая верхняя — 14х16, левая нижняя — 16х14 и правая нижняя — 14х14. Поскольку в большинстве случаев размер рабочей группы составляет 16х16, это ядро будет очень эффективно использовать конвейеры SIMD и доступ к памяти будет очень быстрым.

Справочные материалы

  1. Intel® SDK для приложений OpenCL™ — руководство по оптимизации
  2. Спецификация API Khronos OpenCL 2.0
  3. Спецификация Khronos OpenCL 2.0 для языка C

Viewing all articles
Browse latest Browse all 357

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>