Содержание


Поддержка стандарта OpenMP в компиляторах IBM XL

Comments

Компиляторы IBM® XL помогают обеспечить максимальное быстродействие приложений за счет использования особенностей аппаратной платформы. Кроме того, эти компиляторы поддерживают ряд связанных с производительностью функций, помогающих программистам настраивать и оптимизировать приложения. Поскольку современные компьютеры в большинстве своем являются многоядерными, то одним из наиболее популярных методов повышения быстродействия приложений является параллельная обработка данных.

API-интерфейс OpenMP – это отраслевой стандарт, позволяющий использовать в последовательном коде различные pragma-инструкции и директивы для включения параллелизма. Основными языками спецификации OpenMP являются Fortran, C и C++. Спецификация разработана комитетом по языкам OpenMP, в состав которого входят производители, пользователи и исследователи. Дополнительную информацию вы можете получить на Web-сайте OpenMP (EN).

Поддержка OpenMP в компиляторах XL C/C++ и XL Fortran для платформы Linux on Power с обратным порядком байтов

Компиляторы IBM XL C/C++ V13.1.2 и XL Fortran V15.1.2 для платформы Linux on Power с обратным порядком байтов поддерживают полную спецификацию параллельного программирования OpenMP API V3.1, а также некоторые возможности новейшей (на момент написания этой статьи) спецификации OpenMP API V4.0. OpenMP предоставляет простой и гибкий интерфейс для разработки параллельных прикладных программ. Спецификация OpenMP включает в себя три компонента: pragma-инструкции и директивы компилятора, функции runtime-библиотек и переменные среды. Приложения, соответствующие спецификации OpenMP, являются кросс-платформенными. Спецификация поддерживает приложения, выполняющиеся как параллельно (выполнение в несколько потоков, полная поддержка библиотеки OpenMP), так и последовательно (инструкции и директивы игнорируются, компоновка выполняется с использованием библиотеки-заглушки).

OpenMP-параллелизм включается с помощью опции компилятора –qsmp: при использовании опции –qsmp=omp приложение компилируется в строгом соответствии со стандартом OpenMP. За дополнительной информацией обратитесь к документации по компиляторам XL (раздел Ресурсы).

Что нового в спецификации OpenMP V3.1

Спецификация OpenMP API V3.1 расширяет существующие возможности, позволяя выполнять более тонкую настройку приложений. Также в OpenMP API V3.1 были ослаблены некоторые ограничения, что позволяет более гибко использовать различные сценарии параллельного программирования.

Параллелизм на уровне задач

В предыдущих версиях OpenMP был реализован в основном традиционный параллелизм – например, распараллеливание циклов с заранее известным количеством итераций или создание фиксированного количества независимых параллельных областей исполнения кода. В версии 3.0 был дополнительно реализован нестандартный параллелизм – параллелизм на уровне задач. Новая директива task позволяет распараллеливать нестандартные алгоритмы – например, алгоритмы следования за указателем (pointer chasing) и рекурсивные алгоритмы. Однако несмотря на снижение остроты проблемы, затраты вычислительных ресурсов на распараллеливание задачи могут существенно превзойти затраты на ее непосредственное выполнение. Были введены новые ключевые слова – final (немедленный запуск задачи) и mergeable (предварительное создание среды данных для задачи).

Пример 1. Создание конечных (final) задач

#pragma omp parallel
{
    #pragma omp single
    {
     while (list) {
         #pragma omp task final(list->size < THRESHOLD)
         {
         compute(list->next);
         }
    }
}
}

Из рассмотренного примера видно, что задачи создаются и запускаются в параллельной области. Если размер задачи меньше значения переменной THRESHOLD, то она является конечной (final). Конечные задачи запускаются немедленно и не требуют вычислительных затрат на работу планировщика.

Пример 2. Создание объединяемых (mergeable) задач

void compute(struct S *p)
{
    #pragma omp task final(level < DEPTH) mergeable
    {
    compute(p->next);
    }
}

Функция из второго примера выполняет рекурсивные вычисления, двигаясь по списку. Может оказаться, что на каком-то из уровней этого списка нет смысла создавать новую задачу по причине слишком малого объема вычислений. С помощью ключевого слова mergeable можно запретить компилятору создавать новую среду данных для объединяемой (mergeable) задачи и таким образом избежать вычислительных затрат на ее создание. Эти два новых расширения позволяют более тонко управлять производительностью при использовании параллелизма на уровне задач, что, в свою очередь, уменьшает вычислительные затраты в случаях простых расчетов.

Вложенный параллелизм

Переменная среды OMP_NUM_THREADS задает количество потоков, запускаемых в параллельных областях. Однако при наличии вложенных параллельных областей невозможно напрямую управлять количеством потоков, запускаемых во внутренних областях. Это необходимо учитывать при разработке кода, поскольку в противном случае число запущенных потоков может превысить предельно допустимое, и производительность приложения будет снижена. Спецификация OpenMP V3.1 содержит усовершенствованную переменную среды OMP_NUM_THREADS, которая теперь может задавать количество потоков, запускаемых во внутренних параллельных областях. Значения этой переменной указываются через запятую в виде списка, например, OMP_NUM_THREAD=8,4. Была добавлена группа опрашивающих процедур, включая omp_get_level (уровень вложенной параллельной области), omp_get_ancestor_thread_num (номер родительского потока), omp_get_team_size (размер команды потоков на указанном уровне) и omp_get_active_level (уровень активной вложенной параллельной области). Также в новую спецификацию включены процедуры времени исполнения omp_set_max_active_levels (задание значения максимального количества активных уровней) и omp_get_max_active_levels (получение значения максимального количества активных уровней).

Пример 3. Конструкция с вложенными параллельными областями

#include <omp.h>

int main() {
#pragma omp parallel
    {
    if (omp_get_thread_num()==0) printf("outer parallel: %d\n", omp_get_num_threads());
    
     #pragma omp parallel
     {
     if (omp_get_thread_num()==0)
        printf("inner parallel: %d\n", omp_get_num_threads());
     }
    }
}

Если вы попытаетесь скомпилировать пример 3 в компиляторе XL C/C++, то увидите на экране следующее.

Пример 4. Компиляция приложения с вложенными параллельными областями

$ xlc –qsmp nested_par.c –o nested_par
$ export OMP_NESTED=true
$ export OMP_NUM_THREADS=4,2
$ ./nested_par
outer parallel: 4
inner parallel: 2
inner parallel: 2
inner parallel: 2
inner parallel: 2

Мы видим, что во внешней параллельной области запускаются четыре потока, а во внутренней – два, что соответствует значению "4,2" переменной OMP_NUM_THREADS.

Компиляторы XL C/C++ V13.1.2 и XL Fortran V15.1.2 для платформы Linux on Power с обратным порядком байтов поддерживают стиль вложенного параллелизма OpenMP, который можно включить, присвоив переменной среды OMP_NESTED значение true. По умолчанию вложенный параллелизм отключен для всего приложения, но можно выборочно включать его в отдельных блоках кода с помощью runtime-процедуры omp_set_nested.

Эта возможность позволяет легко настраивать приложения, исходя из характеристик среды, в которой они запускаются, и избегать создания лишних потоков, негативно влияющих на производительность.

Расширение конструкции atomic

В конструкции atomic теперь можно использовать больше различных атомарных операций. Для поддержки операций чтения (read), записи (write) и захвата (capture) были добавлены соответствующие clause-директивы: read, write и capture. Существующая атомарная операция обновления (update) записывается с помощью clause-директивы update.

В примере 5 представлены некоторые атомарные операции.

Пример 5. Атомарные операции OpenMP

! атомарное чтение переменной x
!$omp atomic read
v = x
!$omp end atomic

! атомарная запись переменной x
!$omp atomic write
x = y
!$omp end atomic

! атомарный захват: сохраняется старое значение переменной x, после чего она обновляется
!$omp atomic capture
v = x
x = x + 1
!$omp end atomic

Политика распределения потоков

Для правильной работы некоторых приложений могут потребоваться выделенные аппаратные ресурсы, а перераспределение потоков между центральными процессорами может негативно сказаться на производительности. Чтобы избежать этого, новая спецификация OpenMP содержит дополнительную переменную среды OMP_PROC_BIND, которая включает и отключает перераспределение потоков OpenMP между процессорами в рабочей среде.

Для управления распределением потоков OpenMP между центральными процессорами в компиляторах IBM XL можно использовать переменную среды XLSMPOPTS (опции startproc/stride или procs). Данная возможность является фирменным расширением IBM, поэтому если необходимо обеспечить кросс-платформенность приложения, используйте для распределения потоков переменную OMP_PROC_BIND.

Дополнительные возможности

Ниже рассмотрены некоторые возможности, позволяющие более гибко управлять параллелизмом в различных ситуациях.

Компилятор Fortran позволяет использовать в clause-директиве firstprivate фиктивные аргументы intent(in). Так можно избежать создания временных переменных в процедуре перед ее передачей в блок параллельной обработки. Указатели Fortran теперь можно определять в clause-директивах firstprivate и lastprivate.

В компилятор C/C++ были добавлены операторы приведения min и max, выполняющие соответствующие операции.

Некоторые возможности OpenMP V4.0 и другие усовершенствования

Компиляторы XL C/C++ V13.1.2 и XL Fortran V15.1.2 для платформы Linux on Power с обратным порядком байтов включают новые возможности спецификации OpenMP V4.0 – расширение конструкции atomic и переменную среды OMP_DISPLAY_ENV.

Расширение конструкции atomic

Атомарная операция перестановки (swap) записывается через директиву capture. Сначала сохраняется исходное значение переменной, затем переменная обновляется (см. пример 6).

Пример 6. Атомарная операция перестановки

#pragma omp atomic capture
{
    v = x;
    x = y;
}

Помимо директивы capture существуют и другие виды выражений для более гибкого написания кода.

В компиляторах XL C/C++ V13.1.2 и XL Fortran V15.1.2 для платформы Linux on Power с обратным порядком байтов с целью повышения производительности введена новая реализация конструкции OpenMP atomic. В старой реализации использовались блокировки, обеспечивающие монопольный доступ к ячейкам памяти. В новой реализации используются аппаратные инструкции архитектуры IBM PowerPC®, в которых механизм блокировок не применяется. В результате атомарные операции стали более эффективными и положительно влияют на общую производительность приложений, в которых они используются.

Просмотр runtime-параметров OpenMP

В OpenMP по умолчанию устанавливаются значения внутренних переменных, управляющих выполнением приложений (ICVs – Internal Control Variables). Значения этих ICV-переменных можно изменять с помощью переменных среды или через вызовы runtime-процедур в исходном коде. Чтобы получить значения ICV-переменных через вызовы соответствующих runtime-процедур, необходимо поместить эти вызовы в исходный код и перекомпилировать приложение, а на это требуется время. Реализация OpenMP V4.0 содержит новую переменную среды OMP_DISPLAY_ENV, позволяющую просматривать параметры ICV-переменных во время работы приложения. Это позволяет просматривать значения runtime-параметров и проверять версию runtime-библиотеки, использовавшейся в процессе статической или динамической линковки, в процессе отладки кода. Переменная OMP_DISPLAY_ENV может оказаться полезной в случае неправильной работы приложения после его переноса на новую платформу, когда новые значения ICV-переменных по умолчанию могут отличаться от прежних значений. В этой ситуации OMP_DISPLAY_ENV помогает быстро сравнить значения переменных, найти отличия и внести соответствующие корректировки.

Пример 7. Просмотр параметров времени исполнения с помощью OMP_DISPLAY_ENV

$ export OMP_DISPLAY_ENV=true
$ ./a.out

OPENMP DISPLAY ENVIRONMENT BEGIN
OMP_DISPLAY_ENV='TRUE'

    _OPENMP='201107'
    OMP_DYNAMIC='FALSE'
    OMP_MAX_ACTIVE_LEVELS='5'
    OMP_NESTED='FALSE'
    OMP_NUM_THREADS='96'
    OMP_PROC_BIND='FALSE'
    OMP_SCHEDULE='STATIC,0'
    OMP_STACKSIZE='4194304'
    OMP_THREAD_LIMIT='96'
    OMP_WAIT_POLICY='PASSIVE'
OPENMP DISPLAY ENVIRONMENT END

В примере 7 значением переменной OMP_DISPLAY_ENV является true, поэтому OpenMP выводит на экран все значения ICV-переменных по умолчанию, у которых имеются соответствующие переменные среды Если переменной OMP_DISPLAY_ENV присвоено значение verbose, то также выводится подробная информация от разработчиков (если таковая имеется).

Пример 8. Детальный просмотр runtime-параметров с помощью OMP_DISPLAY_ENV (включая информацию от разработчиков

$ export OMP_DISPLAY_ENV=verbose
$ ./a.out

OPENMP DISPLAY SWITCHES BEGIN
    LOMP_AUTO_PASSIVE_HALF_THREAD='1'
    LOMP_CACHE_LINE_SIZE='256'
    LOMP_CHECK_STACKS='1'
    LOMP_CLEANUP_ON_PROCESS_EXIT='0'
    LOMP_CLEANUP_TO_FORCE_RESCAN='0'
    LOMP_COUNTER_BARRIER='0'
    LOMP_DEBUG='0'
    LOMP_DEFAULT_DELAY='1000'
    LOMP_DEFAULT_SPIN='64'
    LOMP_DEFAULT_YIELD='64'
    LOMP_ENABLE_INLINING='1'
    LOMP_ENABLE_WAIT_PASSIVE_BARRIER='0'
    LOMP_ENABLE_WAIT_PASSIVE_WORKER='1'
    LOMP_FUSSY_INIT='0'
    LOMP_GUIDED_SHARED='1'
    LOMP_ILDE_THREAD_EXIT='0'
    LOMP_XL_LEGACY='0'
    LOMP_G_LEGACY='0'
    LOMP_AUTOPAR_LEGACY='1'
    LOMP_LOOP_CACHE='0'
    LOMP_MASTER_BARRIER_MSYNC='0'
    LOMP_MAX_THREAD='65535'
    LOMP_PARALEL_DISABLE_FAST_PATH='0'
    LOMP_PROC_BIND_40='1'
    LOMP_PROC_BIND_WHEN_OFF='0'
    LOMP_PROC_BIND_WHEN_ON='1'
    LOMP_SEQENTIAL_FAST='1'
    LOMP_TASK_DISABLE_STEAL='0'
    LOMP_TEST='1'
    LOMP_WAIT_LOW_PRIO='1'
    LOMP_WAIT_WITH_YIELD='1'
    OMPT_TIER='0'
    LOMP_TARGET_PPC='0'
    LOMP_TARGET_CUDA='0'
    LOMP_ARCH_POWER='8'
    LOMP_BARRIER_SWMR_DEGREE='2'
    LOMP_BARRIER_WITH_IO_SYNC='1'
OPENMP DISPLAY SWITCHES END

OPENMP DISPLAY RUNTIME BEGIN
    LOMP_VERSION='0.35 for OpenMP 3.1'
    BUILD_LEVEL='OpenMP Runtime Version: 13.1.2(C/C++) and 
    15.1.2(Fortran) Level: 150417 ID: _v1mpguSSEeSbzZ-i2Itj4A'
    TARGET='Linux, 64 bit LE'
OPENMP DISPLAY RUNTIME END

OPENMP DISPLAY ENVIRONMENT BEGIN
    OMP_DISPLAY_ENV='VERBOSE'
    
    _OPENMP='201107'
    OMP_DYNAMIC='FALSE'
    OMP_MAX_ACTIVE_LEVELS='5'
    OMP_NESTED='FALSE'
    OMP_NUM_THREADS='96'
    OMP_PROC_BIND='FALSE'
    OMP_SCHEDULE='STATIC,0'
    OMP_STACKSIZE='4194304'
    OMP_THREAD_LIMIT='96'
    OMP_WAIT_POLICY='PASSIVE'
    XLSMPOPTS=' DELAYS=1000'
    XLSMPOPTS=' NOSTACKCHECK'
    XLSMPOPTS=' PARTHDS=96'
    XLSMPOPTS=' PARTHRESHOLD=    inf'
    XLSMPOPTS=' PROFILEFREQ=16'
    XLSMPOPTS=' SCHEDULE=STATIC=0'
    XLSMPOPTS=' SEQTHRESHOLD=    inf'
    XLSMPOPTS=' SPINS=64'
    XLSMPOPTS=' STACK=4194304'
    XLSMPOPTS=' USRTHDS=0'
    XLSMPOPTS=' YIELDS=64'
OPENMP DISPLAY ENVIRONMENT END

В примере 8 показан вывод в процессе работы компилятора XL. В первом разделе содержатся внутренние runtime-параметры OpenMP. Во втором разделе содержится информация, относящаяся к сборке. Если в системе установлено несколько версий OpenMP, эта информация поможет определить, какая именно версия использовалась для компоновки приложения. Третий раздел содержит информацию о значениях ICV-переменных и расширений IBM.

Заключение

Благодаря поддержке OpenMP API, компиляторы XL позволяют с помощью pragma-директив и инструкций превращать последовательные приложения, написанные на C, C++ или Fortran, в параллельные. Распараллеливая приложения с помощью компиляторов XL, можно задействовать все возможности многоядерного оборудования (например, возможности серверов архитектуры IBM POWER8™). Поддержка некоторых возможностей OpenMP V4.0, реализованная в компиляторах XL C/C++ V13.1.2 и XL Fortran V15.1.2 для платформы Linux on Power с обратным порядком байтов, предоставляет дополнительные способы записи атомарных операций и помогает получать информацию о runtime-параметрах при отладке и переносе приложений на другие платформы.

Ресурсы

  1. Оригинал статьи: OpenMP support in IBM XL compilers (EN).
  2. Официальная спецификация API-интерфейса OpenMP версии 3.1 (июль 2011 г.) (EN).
  3. Официальная спецификация API-интерфейса OpenMP версии 4.0 (июль 2013 г.) (EN).
  4. Документация по компилятору XL C/C++ for Linux 13.1.2 (для платформ с обратным порядком байтов) (EN).
  5. Документация по компилятору XL Fortran for Linux 15.1.2 (для платформ с обратным порядком байтов) (EN).

Ресурсы для скачивания


Комментарии

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux
ArticleID=1022995
ArticleTitle=Поддержка стандарта OpenMP в компиляторах IBM XL
publish-date=11022015