Опубликован: 15.04.2008 | Уровень: специалист | Доступ: платный
Лекция 3:

Загрузка и синхронизация в OpenMP

< Лекция 2 || Лекция 3: 12 || Лекция 4 >

Синхронизация типа master

Синхронизация типа master используется для определения структурного блока программы, который будет выполняться исключительно в главном потоке (параллельном потоке с нулевым номером) из всего набора параллельных потоков. Этот структурный блок следует за директивой

#pragma omp master

в программах, написанных на языке C/C++. В программах на языке Fortran синхронизация типа master устанавливается следующим образом:

c$omp master 
<структурный блок> 
c$omp end master

В примере 3.4 приведен пример фрагмента программы, иллюстрирующий использование синхронизации типа master. В этом примере операторы print и read выполняются исключительно в главном потоке.

! $omp parallel shared (c, scale)
! $omp& private (j, myid)
      myid = omp_get_thread_num ( )
! $omp master
      print *, 'T: ', myid, ' enter scale'
      read *, scale
! $omp end master
! $omp barrier
! $omp do
      do j = 1, N
         c (j) = scale * c (j)
      enddo
! $omp end do
! $omp end parallel
3.4. Пример синхронизации типа master

Синхронизация типа ordered

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

с$omp parallel default (shared) private (I, J)
с$omp do ordered
      do I = 1, N
         do J = 1, M
            Z(I) = Z(I) + X (I, J) * Y(J, I)
         enddo
с$omp ordered
         if (I<21) then
            print*, 'Z (',I,') = ', Z (I)
         endif
с$omp end ordered
      enddo
3.5. Пример программы с синхронизацией типа ordered

Результаты работы программы:

Z (1) = 1007.167786
Z (2) = 1032.933350
Z (3) = 1033.125610
Z (4) = 1009.944641
Z (5) = 1016.547302
Z (6) = 1005.789124
Z (7) = 1025.048584
Z (8) = 1003.904358
Z (9) = 995.5405273
Z (10) = 991.2892456
Z (11) = 1011.334167
Z (12) = 1010.631897
Z (13) = 1009.581848
Z (14) = 976.2397461
Z (15) = 978.1119385
Z (16) = 977.7111816
Z (17) = 971.2011719
Z (18) = 998.4275513
Z (19) = 1018.487000
Z (20) = 978.0640259

В программах на языке C/C++ синхронизация типа ordered описывается следующим образом:

#pragma omp ordered 
<структурный блок>

а в программах, написанных на языке Fortran, синхронизация типа ordered устанавливается так:

c$omp ordered 
<структурный блок> 
c$omp end ordered

В примере 3.5 приведен пример фрагмента программы, иллюстрирующий применение синхронизации типа ordered.

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

Синхронизация типа flush

Синхронизация типа flush используется для обновления значений локальных переменных, перечисленных в качестве аргументов этой команды, в оперативной памяти. После выполнения этой директивы все переменные, перечисленные в этой директиве, имеют одно и то же значение для всех параллельных потоков.

В программах на языке C/C++ синхронизация типа flush описывается следующим образом:

#pragma omp flush(var1, [var2, [..., varN ]])

На языке Fortran эта директива синхронизации типа flush выглядит так:

c$omp flush var1, [var2, [..., varN ]])

Здесь var1, var2, ..., varN - список переменных, значения которых сохраняются в оперативной памяти в момент выполнения директории flush.

Пример фрагмента программы, иллюстрирующий использование синхронизации типа flush, приведен в примере 3.6. В этом примере значения переменной done записываются в оперативную память для того, чтобы все другие процессы имели доступ к актуальным значениям этой переменной.

program flush
        integer, parameter :: M=1600000
        integer, dimension (M) :: c
        integer :: stop, sum, tid
        integer, dimension (0:1) :: done
        integer, external :: omp_get_thread_num

        call omp_set_num_threads (2)
        c = 1
        c (345) = 9
!$omp parallel default (private) shared (done, c, stop)
        tid=omp_get_ thread_num ( )
        done (tid) = 0
        if (tid == 0) then
           neigh = 1
        else
           neigh = 0
        end if
!$omp barrier
        if (tid == 0) then
           do j = 1, M
              if (c j) == 9) stop = j
           enddo
        endif
        done (tid) = 1
!$omp flush (done)
        do while (done(neigh) .eq. 0)
!$omp flush (done)
        enddo
        if (tid == 1) then
           sum=0
           do j = 1, stop - 1
              sum = sum + c (j)
           enddo
        endif
!$omp end parallel
      end program flush
3.6. Пример синхронизации типа flush

Загрузка процессов в OpenMP. Директива schedule

Проблема загрузки параллельных потоков является важной проблемой не только для параллельного программирования с использованием OpenMP, но и для всего параллельного программирования в целом. Эта проблема тесно связана с проблемой балансировки загрузки процессоров параллельных высокопроизводительных вычислительных систем, а также с проблемой повышения эффективности работы параллельных программ. Понятно, что для высокопроизводительной параллельной вычислительной системы успешное решение проблемы балансировки загрузки процессоров является ключом к решению задачи повышения эффективности вычислительной системы в целом. Как известно, процессы по-разному могут использовать вычислительные возможности процессоров. Так, на стадии интенсивных арифметических вычислений коэффициент загрузки процессоров обычно близок к 100%. На стадии интенсивных операций ввода/вывода коэффициент загрузки процессоров меняется в диапазоне от нескольких процентов до десятков процентов. Кроме того, процессоры могут простаивать и в том случа е, когда процессы, переданные им, уже обработаны, а другие процессоры все еще продолжают обрабатывать процессы той же задачи. Для исключения простоев или уменьшения времени простоев применяют различные методы балансировки процессов. Существующие в OpenMP различные методы загрузки процессов также могут быть применены для улучшения балансировки работы параллельных вычислительных систем.

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

schedule( type [ , chunk ] )

Здесь type - параметр, определяющий тип загрузки, а chunk - параметр, который определяет порции данных, пересылаемых между процессами (по умолчанию значение параметра chunk равно 1 ).

В OpenMP параметр type принимает одно из следующих значений:

  • static,
  • dynamic,
  • guided,
  • runtime.

Загрузка типа static

В этом случае вся совокупность загружаемых процессов разбивается на равные порции размера chunk, и эти порции последовательно распределяются между процессорами (или потоками, которые затем и выполняются на этих процессорах) с первого до последнего и т. д.

В качестве примера использования загрузки типа static рассмотрим фрагмент программы на языке Fortran, приведенный в примере 3.7.

с$omp do shared (x) private (i)
с$omp& schedule (static, 1000)
      do i = 1, 12000
         ... work ...
      enddo
3.7. Пример загрузки schedule(static, chunk=1000)

Схема распределения загрузки процессов по процессорам (или потокам ( threads ), которые затем выполняются на процессорах), соответствующая этому примеру, приведена на рис.3.1. Как видно из этой схемы, все 12000 процессов разбиты на 12 порций по 1000 процессов ( chunk=1000 ). Загрузка порций в потоки ( threads ) происходит последовательно. Сначала порции в порядке нумерации загружаются в первый, второй, третий и четвертый потоки, а затем загрузка производится опять в том же порядке, начиная с первого потока и т. д.

Схема загрузки процессоров для программы, приведенной в примере 3.7

Рис. 3.1. Схема загрузки процессоров для программы, приведенной в примере 3.7

Загрузка типа dynamic

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

Пример применения загрузки типа dynamic приведен в следующем фрагменте программы (пример 3.8).

с$omp do shared (x) private (i)
с$omp& schedule (dynamic, 1000)
      do i = 1, 10000
         ... work ...
      enddo
3.8. Пример загрузки schedule(dynamic, chunk=1000)

Загрузка типа guided

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

Пример применения загрузки типа guided приведен в следующем фрагменте программы, изображенном на пример 3.9.

с$omp do shared (x) private (i)
с$omp& schedule (guided, 55)
      do i = 1, 12000
         ... work ...
      enddo
3.9. Пример загрузки schedule(guided, chunk=55)

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

Загрузка типа runtime

В этом случае загрузка порций процессов по потокам (или процессорам) определяется значением переменной окружения OMP_SCHEDULE. Значение этой переменной проверяется перед каждой загрузкой процессов в потоки во время работы программы. По умолчанию оно static.

Два примера задания режимов загрузки типа runtime с помощью команд операционной системы Linux приведены ниже.

$ setenv OMP_SCHEDULE static,1000 
$ setenv OMP_SCHEDULE dynamic

В первом примере через значение переменной окружения в качестве загрузки runtime задается режим static с размером порции равным 1000. Во втором же примере в качестве загрузки runtime задается режим dynamic с размером порции, по умолчанию заданным равным 1.

< Лекция 2 || Лекция 3: 12 || Лекция 4 >
Алексей Ищенко
Алексей Ищенко
Россия, г. Санкт-Петербург
Виолета Белянина
Виолета Белянина
Россия

( ! ) Warning: include_once(./includes/unicode.entities.inc) [<a href='function.include-once'>function.include-once</a>]: failed to open stream: No such file or directory in /.2/var_www_new.intuit.ru/htdocs/includes/unicode.inc on line 340
Call Stack
#TimeMemoryFunctionLocation
13.8641103303760watchdog( )../bootstrap.inc:0
23.8644103306264module_invoke( )../bootstrap.inc:967
33.8644103308120call_user_func_array ( )../module.inc:462
43.8644103308456devel_watchdog( )../module.inc:462
53.8645103309304decode_entities( )../devel.module:382
63.8645103311224drupal_error_handler( )../devel.module:340
73.8646103314848watchdog( )../common.inc:663
83.8646103316952module_invoke( )../bootstrap.inc:967
93.8646103318808call_user_func_array ( )../module.inc:462
103.8646103319144devel_watchdog( )../module.inc:462
113.8647103319840decode_entities( )../devel.module:382

( ! ) Warning: include_once() [<a href='function.include'>function.include</a>]: Failed opening './includes/unicode.entities.inc' for inclusion (include_path='.:/usr/local/zend/var/libraries/Zend_Framework_1/default/library:/usr/local/zend/share/pear') in /.2/var_www_new.intuit.ru/htdocs/includes/unicode.inc on line 340
Call Stack
#TimeMemoryFunctionLocation
13.8641103303760watchdog( )../bootstrap.inc:0
23.8644103306264module_invoke( )../bootstrap.inc:967
33.8644103308120call_user_func_array ( )../module.inc:462
43.8644103308456devel_watchdog( )../module.inc:462
53.8645103309304decode_entities( )../devel.module:382
63.8645103311224drupal_error_handler( )../devel.module:340
73.8646103314848watchdog( )../common.inc:663
83.8646103316952module_invoke( )../bootstrap.inc:967
93.8646103318808call_user_func_array ( )../module.inc:462
103.8646103319144devel_watchdog( )../module.inc:462
113.8647103319840decode_entities( )../devel.module:382

( ! ) Warning: include_once(./includes/unicode.entities.inc) [<a href='function.include-once'>function.include-once</a>]: failed to open stream: No such file or directory in /.2/var_www_new.intuit.ru/htdocs/includes/unicode.inc on line 340
Call Stack
#TimeMemoryFunctionLocation
13.8641103303760watchdog( )../bootstrap.inc:0
23.8644103306264module_invoke( )../bootstrap.inc:967
33.8644103308120call_user_func_array ( )../module.inc:462
43.8644103308456devel_watchdog( )../module.inc:462
53.8645103309304decode_entities( )../devel.module:382
63.8654103311416drupal_error_handler( )../devel.module:340
73.8654103315104watchdog( )../common.inc:663
83.8655103317208module_invoke( )../bootstrap.inc:967
93.8655103319064call_user_func_array ( )../module.inc:462
103.8655103319400devel_watchdog( )../module.inc:462
113.8655103320176decode_entities( )../devel.module:382

( ! ) Warning: include_once() [<a href='function.include'>function.include</a>]: Failed opening './includes/unicode.entities.inc' for inclusion (include_path='.:/usr/local/zend/var/libraries/Zend_Framework_1/default/library:/usr/local/zend/share/pear') in /.2/var_www_new.intuit.ru/htdocs/includes/unicode.inc on line 340
Call Stack
#TimeMemoryFunctionLocation
13.8641103303760watchdog( )../bootstrap.inc:0
23.8644103306264module_invoke( )../bootstrap.inc:967
33.8644103308120call_user_func_array ( )../module.inc:462
43.8644103308456devel_watchdog( )../module.inc:462
53.8645103309304decode_entities( )../devel.module:382
63.8654103311416drupal_error_handler( )../devel.module:340
73.8654103315104watchdog( )../common.inc:663
83.8655103317208module_invoke( )../bootstrap.inc:967
93.8655103319064call_user_func_array ( )../module.inc:462
103.8655103319400devel_watchdog( )../module.inc:462
113.8655103320176decode_entities( )../devel.module:382

( ! ) Warning: include_once(./includes/unicode.entities.inc) [<a href='function.include-once'>function.include-once</a>]: failed to open stream: No such file or directory in /.2/var_www_new.intuit.ru/htdocs/includes/unicode.inc on line 340
Call Stack
#TimeMemoryFunctionLocation
13.8660103304304watchdog( )../bootstrap.inc:0
23.8660103306408module_invoke( )../bootstrap.inc:967
33.8660103308264call_user_func_array ( )../module.inc:462
43.8660103308600devel_watchdog( )../module.inc:462
53.8661103309304decode_entities( )../devel.module:382
63.8661103311224drupal_error_handler( )../devel.module:340
73.8661103314832watchdog( )../common.inc:663
83.8661103316936module_invoke( )../bootstrap.inc:967
93.8661103318792call_user_func_array ( )../module.inc:462
103.8661103319128devel_watchdog( )../module.inc:462
113.8662103319824decode_entities( )../devel.module:382

( ! ) Warning: include_once() [<a href='function.include'>function.include</a>]: Failed opening './includes/unicode.entities.inc' for inclusion (include_path='.:/usr/local/zend/var/libraries/Zend_Framework_1/default/library:/usr/local/zend/share/pear') in /.2/var_www_new.intuit.ru/htdocs/includes/unicode.inc on line 340
Call Stack
#TimeMemoryFunctionLocation
13.8660103304304watchdog( )../bootstrap.inc:0
23.8660103306408module_invoke( )../bootstrap.inc:967
33.8660103308264call_user_func_array ( )../module.inc:462
43.8660103308600devel_watchdog( )../module.inc:462
53.8661103309304decode_entities( )../devel.module:382
63.8661103311224drupal_error_handler( )../devel.module:340
73.8661103314832watchdog( )../common.inc:663
83.8661103316936module_invoke( )../bootstrap.inc:967
93.8661103318792call_user_func_array ( )../module.inc:462
103.8661103319128devel_watchdog( )../module.inc:462
113.8662103319824decode_entities( )../devel.module:382

( ! ) Warning: include_once(./includes/unicode.entities.inc) [<a href='function.include-once'>function.include-once</a>]: failed to open stream: No such file or directory in /.2/var_www_new.intuit.ru/htdocs/includes/unicode.inc on line 340
Call Stack
#TimeMemoryFunctionLocation
13.8660103304304watchdog( )../bootstrap.inc:0
23.8660103306408module_invoke( )../bootstrap.inc:967
33.8660103308264call_user_func_array ( )../module.inc:462
43.8660103308600devel_watchdog( )../module.inc:462
53.8661103309304decode_entities( )../devel.module:382
63.8667103311416drupal_error_handler( )../devel.module:340
73.8667103315104watchdog( )../common.inc:663
83.8667103317208module_invoke( )../bootstrap.inc:967
93.8667103319064call_user_func_array ( )../module.inc:462
103.8667103319400devel_watchdog( )../module.inc:462
113.8667103320176decode_entities( )../devel.module:382

( ! ) Warning: include_once() [<a href='function.include'>function.include</a>]: Failed opening './includes/unicode.entities.inc' for inclusion (include_path='.:/usr/local/zend/var/libraries/Zend_Framework_1/default/library:/usr/local/zend/share/pear') in /.2/var_www_new.intuit.ru/htdocs/includes/unicode.inc on line 340
Call Stack
#TimeMemoryFunctionLocation
13.8660103304304watchdog( )../bootstrap.inc:0
23.8660103306408module_invoke( )../bootstrap.inc:967
33.8660103308264call_user_func_array ( )../module.inc:462
43.8660103308600devel_watchdog( )../module.inc:462
53.8661103309304decode_entities( )../devel.module:382
63.8667103311416drupal_error_handler( )../devel.module:340
73.8667103315104watchdog( )../common.inc:663
83.8667103317208module_invoke( )../bootstrap.inc:967
93.8667103319064call_user_func_array ( )../module.inc:462
103.8667103319400devel_watchdog( )../module.inc:462
113.8667103320176decode_entities( )../devel.module:382