С. антоновпараллельноепрограммированиесиспользованиемтехнологииopenMP
Скачать 0.55 Mb.
|
omp_set_max_active_levels(). Си: void omp_set_max_active_levels(int max); Фортран: subroutine omp_set_max_active_levels(max) integer max Если значение max превышает максимально допустимое в системе, будет ус- тановлено максимально допустимое в системе значение. При вызове из па- раллельной области результат выполнения зависит от реализации. Значение переменной OMP_MAX_ACTIVE_LEVELS может быть получено при помощи вызова функции omp_get_max_active_levels() Си: int omp_get_max_active_levels(void); Фортран: integer function omp_get_max_active_levels() Функция omp_get_level() выдаёт для вызвавшей нити количество вложен- ных параллельных областей в данном месте кода. Си: int omp_get_level(void); Фортран: integer function omp_get_level() При вызове из последовательной области функция возвращает значение 0 Функция omp_get_ancestor_thread_num() возвращает для уровня вложен- ности параллельных областей, заданного параметром level , номер нити, по- родившей данную нить. Си: int omp_get_ancestor_thread_num(int level); Фортран: integer function omp_get_ancestor_thread_num(level) integer level 69 Если level меньше нуля или больше текущего уровня вложенности, возвра- щается -1 . Если level=0 , функция вернёт 0 , а если level=omp_get_level() , вызов эквивалентен вызову функции omp_get_thread_num() Функция omp_get_team_size() возвращает для заданного параметром level уровня вложенности параллельных областей количество нитей, порождённых одной родительской нитью. Си: int omp_get_team_size(int level); Фортран: integer function omp_get_team_size(level) integer level Если level меньше нуля или больше текущего уровня вложенности, возвра- щается -1 . Если level=0 , функция вернёт 1 , а если level=omp_get_level() , вызов эквивалентен вызову функции omp_get_num_threads() Функция omp_get_active_level() возвращает для вызвавшей нити количе- ство вложенных параллельных областей, обрабатываемых более чем одной нитью, в данном месте кода. Си: int omp_get_active_level(void); Фортран: integer function omp_get_active_level() При вызове из последовательной области возвращает значение 0 Переменная среды OMP_STACKSIZE задаёт размер стека для создаваемых из программы нитей. Значение переменной может задаваться в виде size | sizeB | sizeK | sizeM | sizeG , где size – положительное целое число, а буквы B , K , M , G задают соответственно, байты, килобайты, мегабайты и гига- байты. Если ни одной из этих букв не указано, размер задаётся в килобайтах. Если задан неправильный формат или невозможно выделить запрошенный размер стека, результат будет зависеть от реализации. Например, в Linux в командной оболочке bash задать размер стека можно при помощи следующей команды: export OMP_STACKSIZE=2000K 70 Переменная среды OMP_WAIT_POLICY задаёт поведение ждущих процессов. Если задано значение ACTIVE , то ждущему процессу будут выделяться циклы процессорного времени, а при значении PASSIVE ждущий процесс может быть отправлен в спящий режим, при этом процессор может быть назначен другим процессам. Переменная среды OMP_THREAD_LIMIT задаёт максимальное число нитей, до- пустимых в программе. Если значение переменной не является положитель- ным целым числом или превышает максимально допустимое в системе число процессов, поведение программы будет зависеть от реализации. Значение пе- ременной может быть получено при помощи процедуры omp_get_thread_limit() Си: int omp_get_thread_limit(void); Фортран: integer function omp_get_thread_limit() 71 Использование OpenMP Если целевая вычислительная платформа является многопроцессорной и/или многоядерной, то для повышения быстродействия программы нужно задей- ствовать все доступные пользователю вычислительные ядра. Чаще всего ра- зумно порождать по одной нити на вычислительное ядро, хотя это не являет- ся обязательным требованием. Например, для первоначальной отладки может быть вполне достаточно одноядерного процессора, на котором порождается несколько нитей, работающих в режиме разделения времени. Порождение и уничтожение нитей в OpenMP являются относительно недорогими опера- циями, однако надо помнить, что многократное совершение этих действий (например, в цикле) может повлечь существенное увеличение времени рабо- ты программы. Для того чтобы получить параллельную версию, сначала необходимо опре- делить ресурс параллелизма программы, то есть, найти в ней участки, кото- рые могут выполняться независимо разными нитями. Если таких участков относительно немного, то для распараллеливания чаще всего используются конструкции, задающие конечный (неитеративный) параллелизм, например, параллельные секции, конструкция workshare или низкоуровневое распа- раллеливание по номеру нити. Однако, как показывает практика, наибольший ресурс параллелизма в про- граммах сосредоточен в циклах. Поэтому наиболее распространенным спо- собом распараллеливания является то или иное распределение итераций цик- лов. Если между итерациями некоторого цикла нет информационных зависимостей, то их можно каким-либо способом раздать разным процессо- рам для одновременного исполнения. Различные способы распределения итераций позволяют добиваться максимально равномерной загрузки нитей, между которыми распределяются итерации цикла. Статический способ распределения итераций позволяет уже в момент напи- сания программы точно определить, какой нити достанутся какие итерации. Однако он не учитывает текущей загруженности процессоров, соотношения времён выполнения различных итераций и некоторых других факторов. Эти факторы в той или иной степени учитываются динамическими способами распределения итераций. Кроме того, возможно отложить решение по спосо- бу распределения итераций на время выполнения программы (например, вы- бирать его, исходя из текущей загруженности нитей) или возложить выбор распределения на компилятор и/или систему выполнения. Обмен данными в OpenMP происходит через общие переменные. Это приво- дит к необходимости разграничения одновременного доступа разных нитей к общим данным. Для этого предусмотрены достаточно развитые средства 72 синхронизации. При этом нужно учитывать, что использование излишних синхронизаций может существенно замедлить программу. Использование идеи инкрементального распараллеливания позволяет при помощи OpenMP быстро получить параллельный вариант программы. Взяв за основу последовательный код, пользователь шаг за шагом добавляет но- вые директивы, описывающие новые параллельные области. Нет необходи- мости сразу распараллеливать всю программу, её создание ведется последо- вательно, что упрощает и процесс программирования, и отладку. Программа, созданная с использованием технологии OpenMP, может быть использована и в качестве последовательной программы. Таким образом, нет необходимости поддерживать последовательную и параллельную версии. Директивы OpenMP просто игнорируются последовательным компилятором, а для вызова функций OpenMP могут быть подставлены специальные «за- глушки» (stubs), текст которых приведен в описании стандарта. Они гаранти- руют корректную работу программы в последовательном случае – нужно только перекомпилировать программу и подключить другую библиотеку. Одним из достоинств OpenMP его разработчики считают поддержку так на- зываемых оторванных (orphaned) директив. Это предполагает, что директи- вы синхронизации и распределения работы могут не входить непосредствен- но в лексический контекст параллельной области. Например, можно вставлять директивы в вызываемую подпрограмму, предполагая, что её вы- зов произойдёт из параллельной области. OpenMP может использоваться совместно с другими технологиями парал- лельного программирования, например, с MPI. Обычно в этом случае MPI используется для распределения работы между несколькими вычислитель- ными узлами, а OpenMP затем используется для распараллеливания на одном узле. 73 Примеры программ Пример 30 реализует простейшую программу вычисления числа Пи. Для распараллеливания достаточно добавить в последовательную программу все- го две строчки. #include double f(double y) {return(4.0/(1.0+y*y));} int main() { double w, x, sum, pi; int i; int n = 1000000; w = 1.0/n; sum = 0.0; #pragma omp parallel for private(x) shared(w)\ reduction(+:sum) for(i=0; i < n; i++) { x = w*(i-0.5); sum = sum + f(x); } pi = w*sum; printf("pi = %f\n", pi); } Пример 30a. ВычислениечислаПинаязыкеСи. program compute_pi parameter (n = 1000000) integer i double precision w, x, sum, pi, f, y f(y) = 4.d0/(1.d0+y*y) w = 1.0d0/n sum = 0.0d0; !$omp parallel do private(x) shared(w) !$omp& reduction(+:sum) do i=1,n x = w*(i-0.5d0) sum = sum + f(x) end do pi = w*sum print *, 'pi = ', pi end Пример 30b. ВычислениечислаПинаязыкеФортран. 74 Пример 31 реализует простейшую программу, реализующую перемножение двух квадратных матриц. В программе замеряется время на основной вычис- лительный блок, не включающий начальную инициализацию. В основном вычислительном блоке программы на языке Фортран изменён порядок цик- лов с параметрами i и j для лучшего соответствия правилам размещения эле- ментов массивов. #include #include #define N 4096 double a[N][N], b[N][N], c[N][N]; int main() { int i, j, k; double t1, t2; // инициализация матриц for (i=0; i for (j=0; j a[i][j]=b[i][j]=i*j; t1=omp_get_wtime(); // основной вычислительный блок #pragma omp parallel for shared(a, b, c) private(i, j, k) for(i=0; i for(j=0; j c[i][j] = 0.0; for(k=0; k } } t2=omp_get_wtime(); printf("Time=%lf\n", t2-t1); } Пример 31a. ПеремножениематрицнаязыкеСи. 75 program matrmult include "omp_lib.h" integer N parameter(N=4096) common /arr/ a, b, c double precision a(N, N), b(N, N), c(N, N) integer i, j, k double precision t1, t2 C инициализация матриц do i=1, N do j=1, N a(i, j)=i*j b(i, j)=i*j end do end do t1=omp_get_wtime() C основной вычислительный блок !$omp parallel do shared(a, b, c) private(i, j, k) do j=1, N do i=1, N c(i, j) = 0.0 do k=1, N c(i, j)=c(i, j)+a(i, k)*b(k, j) end do end do end do t2=omp_get_wtime() print *, "Time=", t2-t1 end Пример 31b. ПеремножениематрицнаязыкеФортран. В таблице 2 приведены времена выполнения примера 31 на узле суперком- пьютера СКИФ МГУ «ЧЕБЫШЁВ» [9]. Использовался компилятор Intel 11.0 без дополнительных опций оптимизации, кроме –openmp Количество нитей 1 2 4 8 Си 165.442016 114.413227 68.271149 39.039399 Фортран 164.433444 115.100835 67.953780 39.606582 Таблица 2. Временавыполненияпроизведенияматрицнаузле суперкомпьютераСКИФМГУ «ЧЕБЫШЁВ». 76 Литература 1. OpenMP Architecture Review Board (http://www.openmp.org/). 2. The Community of OpenMP Users, Researchers, Tool Developers and Pro- viders (http://www.compunity.org/). 3. OpenMP Application Program Interface Version 3.0 May 2008 (http://www.openmp.org/mp-documents/spec30.pdf). 4. Что такое OpenMP? (http://parallel.ru/tech/tech_dev/openmp.html). 5. Воеводин В.В., Воеводин Вл.В. Параллельные вычисления. СПб.: БХВ-Петербург, 2002. - 608 с. 6. Barbara Chapman, Gabriele Jost, Ruud van der Pas. Using OpenMP: port- able shared memory parallel programming (Scientific and Engineering Computation). Cambridge, Massachusetts: The MIT Press., 2008. - 353 pp. 7. Антонов А.С. Введение в параллельные вычисления. Методическое пособие.-М.: Изд-во Физического факультета МГУ, 2002. - 70 с. 8. Антонов А.С. Параллельное программирование с использованием тех- нологии MPI: Учебное пособие. -М.: Изд-во МГУ, 2004. - 71 с. 9. Суперкомпьютерный комплекс Московского университета (http://parallel.ru/cluster/). Учебное издание АнтоновАлександрСергеевич ПАРАЛЛЕЛЬНОЕ ПРОГРАММИРОВАНИЕ С ИСПОЛЬЗОВАНИЕМТЕХНОЛОГИИ OpenMP Подписано в печать 18.03.2009. Формат 60х84/16. Бумага офсетная №1. Печать ризо. Усл. печ. л. 4,75. Уч.-изд. л. 5,0. Тираж 100 экз. Заказ № 1. Ордена «Знак Почета» издательство Московского университета. 125009, Москва, ул. Б. Никитская, 5/7. Участок оперативной печати НИВЦ МГУ. 119992, ГСП-2, Москва, НИВЦ МГУ. |