'

Технология параллельного программирования OpenMP

Понравилась презентация – покажи это...





Слайд 0

Технология параллельного программирования OpenMP Бахтин Владимир Александрович к.ф.-м.н., зав. сектором Института прикладной математики им М.В.Келдыша РАН ассистент кафедры системного программирования факультета вычислительной математики и кибернетики Московского университета им. М.В. Ломоносова


Слайд 1

1 июля Москва, 2013 Технология параллельного программирования OpenMP 2 из 125 OpenMP – модель параллелизма по управлению Конструкции распределения работы Конструкции для синхронизации нитей Система поддержки выполнения OpenMP-программ. OpenMP 4.0 Содержание


Слайд 2

1 июля Москва, 2013 Технология параллельного программирования OpenMP 3 из 125 OpenMP Fortran 1.1 OpenMP C/C++ 1.0 OpenMP Fortran 2.0 OpenMP C/C++ 2.0 1998 1999 2002 OpenMP Fortran 1.0 1997 OpenMP F/C/C++ 2.5 2005 OpenMP F/C/C++ 3.0 2008 OpenMP F/C/C++ 3.1 2011 История OpenMP


Слайд 3

1 июля Москва, 2013 Технология параллельного программирования OpenMP 4 из 125 AMD Cray Fujitsu HP IBM Intel NEC The Portland Group, Inc. Oracle Corporation Microsoft Texas Instrument CAPS-Enterprise NVIDIA Convey Computer OpenMP Architecture Review Board ANL ASC/LLNL cOMPunity EPCC LANL NASA Red Hat RWTH Aachen University Texas Advanced Computing Center SNL- Sandia National Lab BSC - Barcelona Supercomputing Center


Слайд 4

OpenMP 3.1: Intel 12.0: Linux, Windows and MacOS Oracle Solaris Studio12.3: Linux and Solaris GNU gcc (4.7.0) OpenMP 3.0: PGI 8.0: Linux and Windows IBM 10.1: Linux and AIX Cray: Cray XT series Linux environment Absoft Pro FortranMP: 11.1 NAG Fortran Complier 5.3 Предыдущие версии OpenMP: Lahey/Fujitsu Fortran 95 PathScale HP Microsoft Visual Studio 2008 C++ 1 июля Москва, 2013 Технология параллельного программирования OpenMP 5 из 125 Компиляторы, поддеживающие OpenMP


Слайд 5

1 июля Москва, 2013 Технология параллельного программирования OpenMP 6 из 125 omp_set_lock(lck) #pragma omp parallel for private(a, b) #pragma omp critical C$OMP PARALLEL DO SHARED(A,B,C) C$OMP PARALLEL REDUCTION (+: A, B) CALL OMP_INIT_LOCK (LCK) CALL OMP_TEST_LOCK(LCK) SETENV OMP_SCHEDULE “STATIC,4” CALL OMP_SET_NUM_THREADS(10) C$OMP DO LASTPRIVATE(XX) C$OMP ORDERED C$OMP SINGLE PRIVATE(X) C$OMP SECTIONS C$OMP MASTER C$OMP ATOMIC C$OMP FLUSH C$OMP PARALLEL DO ORDERED PRIVATE (A, B, C) C$OMP THREADPRIVATE(/ABC/) C$OMP PARALLEL COPYIN(/blk/) nthrds = OMP_GET_NUM_PROCS() C$OMP BARRIER OpenMP: API для написания многонитевых приложений Множество директив компилятора, набор функции библиотеки системы поддержки, переменные окружения Облегчает создание многонитиевых программ на Фортране, C и C++ Обобщение опыта создания параллельных программ для SMP и DSM систем за последние 20 лет Обзор основных возможностей OpenMP


Слайд 6

1 июля Москва, 2013 Технология параллельного программирования OpenMP 7 из 125 END PARALLEL PARALLEL END PARALLEL PARALLEL Fork-Join параллелизм: Главная (master) нить порождает группу (team) нитей по мере небходимости. Параллелизм добавляется инкрементально. END PARALLEL PARALLEL Параллельные области Выполнение OpenMP-программы


Слайд 7

В модели программирования с разделяемой памятью: Большинство переменных по умолчанию считаются shared Глобальные переменные совместно используются всеми нитями (shared) : Фортран: COMMON блоки, SAVE переменные, MODULE переменные Си: file scope, static Динамически выделяемая память (ALLOCATE, malloc, new) Но не все переменные являются разделяемыми ... Стековые переменные в подпрограммах (функциях), вызываемых из параллельного региона, являются private. Переменные объявленные внутри блока операторов параллельного региона являются приватными. Счетчики циклов витки которых распределяются между нитями при помощи конструкций for и parallel for. 1 июля Москва, 2013 Технология параллельного программирования OpenMP 8 из 125 Классы переменных


Слайд 8

double Array1[100]; int main() { int Array2[100]; #pragma omp parallel { int iam = omp_get_thread_num(); work(Array2, iam); } printf(“%d\n”, Array2[0]); } Технология параллельного программирования OpenMP extern double Array1[10]; void work(int *Array, int iam) { double TempArray[10]; static int count; ... } END PARALLEL PARALLEL TempArray, iam TempArray, iam TempArray, iam Array1, Array2, count Array1, Array2, count Классы переменных 1 июля Москва, 2013 9 из 125


Слайд 9

Можно изменить класс переменной при помощи конструкций: shared (список переменных) private (список переменных) firstprivate (список переменных) lastprivate (список переменных) threadprivate (список переменных) default (private | shared | none) 1 июля Москва, 2013 Технология параллельного программирования OpenMP 10 из 125 Классы переменных


Слайд 10

Конструкция «private(var)» создает локальную копию переменной «var» в каждой из нитей. Значение переменной не инициализировано Приватная копия не связана с оригинальной переменной В OpenMP 2.5 значение переменной «var» не определено после завершения параллельной конструкции sum = -1.0; #pragma omp parallel for private (i,j,sum) for (i=0; i< m; i++) { sum = 0.0; for (j=0; j< n; j++) sum +=b[i][j]*c[j]; a[i] = sum; } sum == -1.0 1 июля Москва, 2013 Технология параллельного программирования OpenMP 11 из 125 Конструкция private


Слайд 11

«firstprivate» является специальным случаем «private» Инициализирует каждую приватную копию соответствующим значением из главной (master) нити. BOOL FirstTime=TRUE; #pragma omp parallel for firstprivate(FirstTime) for (row=0; row<height; row++) { if (FirstTime == TRUE) { FirstTime = FALSE; FirstWork (row); } AnotherWork (row); } 1 июля Москва, 2013 Технология параллельного программирования OpenMP 12 из 125 Конструкция firstprivate


Слайд 12

1 июля Москва, 2013 Технология параллельного программирования OpenMP 13 из 125 lastprivate передает значение приватной переменной, посчитанной на последней итерации в глобальную переменную. int i; #pragma omp parallel { #pragma omp for lastprivate(i) for (i=0; i<n-1; i++) a[i] = b[i] + b[i+1]; } a[i]=b[i]; /*i == n-1*/ Конструкция lastprivate


Слайд 13

Отличается от применения конструкции private: private скрывает глобальные переменные threadprivate – переменные сохраняют глобальную область видимости внутри каждой нити #pragma omp threadprivate (Var) 1 июля Москва, 2013 Технология параллельного программирования OpenMP 14 из 125 END PARALLEL PARALLEL END PARALLEL PARALLEL Var = 1 Var = 2 … = Var … = Var Если количество нитей не изменилось, то каждая нить получит значение, посчитанное в предыдущей параллельной области. Директива threadprivate


Слайд 14

1 июля Москва, 2013 Технология параллельного программирования OpenMP 15 из 125 itotal = 100 #pragma omp parallel private(np,each) { np = omp_get_num_threads() each = itotal/np ……… } itotal = 100 #pragma omp parallel default(none) private(np,each) shared (itotal) { np = omp_get_num_threads() each = itotal/np ……… } Меняет класс переменной по умолчанию: default (shared) – действует по умолчанию default (private) – есть только в Fortran default (firstprivate) – есть только в Fortran OpenMP 3.1 default (none) – требует определить класс для каждой переменной Конструкция default


Слайд 15

#pragma omp parallel [ клауза[ [, ] клауза] ...] структурный блок где клауза одна из : default(shared | none) private(list) firstprivate(list) shared(list) reduction(operator: list) if(scalar-expression) num_threads(integer-expression) copyin(list) 1 июля Москва, 2013 Технология параллельного программирования OpenMP 16 из 125 Параллельная область (директива parallel)


Слайд 16

1 июля Москва, 2013 Технология параллельного программирования OpenMP 17 из 125 Вычисление числа ?


Слайд 17

1 июля Москва, 2013 Технология параллельного программирования OpenMP 18 из 125 #include <stdio.h> int main () { int n =100000, i; double pi, h, sum, x; h = 1.0 / (double) n; sum = 0.0; for (i = 1; i <= n; i ++) { x = h * ((double)i - 0.5); sum += (4.0 / (1.0 + x*x)); } pi = h * sum; printf("pi is approximately %.16f”, pi); return 0; } Вычисление числа ?. Последовательная программа


Слайд 18

1 июля Москва, 2013 Технология параллельного программирования OpenMP 19 из 125 #include <omp.h> int main () { int n =100000, i; double pi, h, sum, x; h = 1.0 / (double) n; sum = 0.0; #pragma omp parallel default (none) private (i,x) shared (n,h,sum) { double local_sum = 0.0; int id = omp_get_thread_num(); int numt = omp_get_num_threads(); for (i = id + 1; i <= n; i=i+numt) { x = h * ((double)i - 0.5); local_sum += (4.0 / (1.0 + x*x)); } #pragma omp critical sum += local_sum; } pi = h * sum; printf("pi is approximately %.16f”, pi); return 0; } #pragma omp critical [(name)] структурный блок Вычисление числа ?. Параллельная программа


Слайд 19

1 июля Москва, 2013 Технология параллельного программирования OpenMP 20 из 125 #include <stdio.h> #include <omp.h> int main () { int n =100000, i; double pi, h, sum, x; h = 1.0 / (double) n; sum = 0.0; #pragma omp parallel default (none) private (i,x) shared (n,h) reduction(+:sum) { int id = omp_get_thread_num(); int numt = omp_get_num_threads(); for (i = id + 1; i <= n; i=i+numt) { x = h * ((double)i - 0.5); sum += (4.0 / (1.0 + x*x)); } } pi = h * sum; printf("pi is approximately %.16f”, pi); return 0; } Вычисление числа ? на OpenMP. Клауза reduction


Слайд 20

reduction(operator:list) Внутри паралельной области для каждой переменной из списка list создается копия этой переменной. Эта переменная инициализируется в соответствии с оператором operator (например, 0 для «+»). Для каждой нити компилятор заменяет в параллельной области обращения к редукционной переменной на обращения к созданной копии. По завершении выполнения параллельной области осуществляется объединение полученных результатов. 21 из 125 Клауза reduction Технология параллельного программирования OpenMP 1 июля Москва, 2013


Слайд 21

1 июля Москва, 2013 Технология параллельного программирования OpenMP 22 из 125 OpenMP – модель параллелизма по управлению Конструкции распределения работы Конструкции для синхронизации нитей Система поддержки выполнения OpenMP-программ OpenMP 4.0 Содержание


Слайд 22

1 июля Москва, 2013 Технология параллельного программирования OpenMP 23 из 125 Распределение витков циклов (директива for) Циклы с зависимостью по данным. Организация конвейерного выполнения для циклов с зависимостью по данным. Распределение нескольких структурных блоков между нитями (директива SECTION). Выполнение структурного блока одной нитью (директива single) Распределение операторов одного структурного блока между нитями (директива WORKSHARE) Понятие задачи Конструкции распределения работы


Слайд 23

1 июля Москва, 2013 Технология параллельного программирования OpenMP 24 из 125 Вычисление числа ?


Слайд 24

1 июля Москва, 2013 Технология параллельного программирования OpenMP 25 из 125 #include <stdio.h> #include <omp.h> int main () { int n =100000, i; double pi, h, sum, x; h = 1.0 / (double) n; sum = 0.0; #pragma omp parallel default (none) private (i,x) shared (n,h) reduction(+:sum) { int id = omp_get_thread_num(); int numt = omp_get_num_threads(); for (i = id + 1; i <= n; i=i+numt) { x = h * ((double)i - 0.5); sum += (4.0 / (1.0 + x*x)); } } pi = h * sum; printf("pi is approximately %.16f”, pi); return 0; } Вычисление числа ? на OpenMP


Слайд 25

1 июля Москва, 2013 Технология параллельного программирования OpenMP 26 из 125 #include <stdio.h> #include <omp.h> int main () { int n =100000, i; double pi, h, sum, x; h = 1.0 / (double) n; sum = 0.0; #pragma omp parallel default (none) private (i,x) shared (n,h) reduction(+:sum) { #pragma omp for schedule (static,1) for (i = 1; i <= n; i++) { x = h * ((double)i - 0.5); sum += (4.0 / (1.0 + x*x)); } } pi = h * sum; printf("pi is approximately %.16f”, pi); return 0; } Вычисление числа ? на OpenMP. Клауза reduction


Слайд 26

Технология параллельного программирования OpenMP int main () { int n =100000, i; double pi, h, sum, x; h = 1.0 / (double) n; sum = 0.0; #pragma omp parallel default (none) private (i,x) shared (n,h) reduction(+:sum) { int iam = omp_get_thread_num(); int numt = omp_get_num_threads(); int start = iam * n / numt + 1; int end = (iam + 1) * n / numt; if (iam == numt-1) end = n; for (i = start; i <= end; i++) { x = h * ((double)i - 0.5); sum += (4.0 / (1.0 + x*x)); } } pi = h * sum; printf(“pi is approximately %.16f”, pi); return 0; } Вычисление числа ? на OpenMP 1 июля Москва, 2013 27 из 125


Слайд 27

1 июля Москва, 2013 Технология параллельного программирования OpenMP 28 из 125 #include <stdio.h> #include <omp.h> int main () { int n =100, i; double pi, h, sum, x; h = 1.0 / (double) n; sum = 0.0; #pragma omp parallel default (none) private (i,x) shared (n,h) reduction(+:sum) { #pragma omp for schedule (static) for (i = 1; i <= n; i++) { x = h * ((double)i - 0.5); sum += (4.0 / (1.0 + x*x)); } } pi = h * sum; printf(“pi is approximately %.16f”, pi); return 0; } Вычисление числа ? на OpenMP


Слайд 28

#pragma omp for [клауза[[,]клауза] ... ] for (init-expr; test-expr; incr-expr) структурный блок где клауза одна из : private(list) firstprivate(list) lastprivate(list) reduction(operator: list) schedule(kind[, chunk_size]) collapse(n) ordered nowait 1 июля Москва, 2013 Технология параллельного программирования OpenMP 29 из 125 Распределение витков цикла


Слайд 29

init-expr : var = loop-invariant-expr1 | integer-type var = loop-invariant-expr1 | random-access-iterator-type var = loop-invariant-expr1 | pointer-type var = loop-invariant-expr1 test-expr: var relational-op loop-invariant-expr2 | loop-invariant-expr2 relational-op var incr-expr: ++var | var++ | --var | var -- | var += loop-invariant-integer- expr | var -= loop-invariant-integer- expr | var = var + loop-invariant-integer- expr | var = loop-invariant-integer- expr + var | var = var - loop-invariant-integer- expr 1 июля Москва, 2013 Технология параллельного программирования OpenMP 30 из 125 relational-op: < | <= | > | >= var: signed or unsigned integer type | random access iterator type | pointer type Распределение витков цикла


Слайд 30

#include <vector> void iterator_example() { std::vector<int> vec(23); std::vector<int>::iterator it; #pragma omp parallel for default(none) shared(vec) for (it = vec.begin(); it < vec.end(); it++) { // do work with *it // } } 1 июля Москва, 2013 Технология параллельного программирования OpenMP 31 из 125 Parallel Random Access Iterator Loop (OpenMP 3.0)


Слайд 31

void pointer_example () { char a[N]; #pragma omp for default (none) shared (a,N) for (char *p = a; p < (a+N); p++ ) { use_char (p); } } for (char *p = a; p != (a+N); p++ ) - ошибка 1 июля Москва, 2013 Технология параллельного программирования OpenMP 32 из 125 Использование указателей в цикле (OpenMP 3.0)


Слайд 32

void work(int i, int j) {} void good_collapsing(int n) { int i, j; #pragma omp parallel default(shared) { #pragma omp for collapse (2) for (i=0; i<n; i++) { for (j=0; j < n; j++) work(i, j); } } } Клауза collapse: collapse (положительная целая константа) 1 июля Москва, 2013 Технология параллельного программирования OpenMP 33 из 125 Распределение витков многомерных циклов. Клауза collapse (OpenMP 3.0)


Слайд 33

void work(int i, int j) {} void error_collapsing(int n) { int i, j; #pragma omp parallel default(shared) { #pragma omp for collapse (2) for (i=0; i<n; i++) { work_with_i (i); // Ошибка for (j=0; j < n; j++) work(i, j); } } } Клауза collapse может быть использована только для распределения витков тесно-вложенных циклов. 1 июля Москва, 2013 Технология параллельного программирования OpenMP 34 из 125 Распределение витков многомерных циклов. Клауза collapse (OpenMP 3.0)


Слайд 34

void work(int i, int j) {} void error_collapsing(int n) { int i, j; #pragma omp parallel default(shared) { #pragma omp for collapse (2) for (i=0; i<n; i++) { for (j=0; j < i; j++) // Ошибка work(i, j); } } } Клауза collapse может быть использована только для распределения витков циклов с прямоугольным индексным пространством. 1 июля Москва, 2013 Технология параллельного программирования OpenMP 35 из 125 Распределение витков многомерных циклов. Клауза collapse (OpenMP 3.0)


Слайд 35

Клауза schedule: schedule(алгоритм планирования[, число_итераций]) Где алгоритм планирования один из: schedule(static[, число_итераций]) - статическое планирование; schedule(dynamic[, число_итераций]) - динамическое планирование; schedule(guided[, число_итераций]) - управляемое планирование; schedule(runtime) - планирование в период выполнения; schedule(auto) - автоматическое планирование (OpenMP 3.0). #pragma omp parallel for private(tmp) shared (a) schedule (runtime) for (int i=0; i<N-2; i++) for (int j = i+1; j< N-1; j++) { tmp = a[i][j]; a[i][j]=a[j][i]; a[j][i]=tmp; } 1 июля Москва, 2013 Технология параллельного программирования OpenMP 36 из 125 Распределение витков цикла. Клауза schedule


Слайд 36

#pragma omp parallel for schedule(static) for(int i = 1; i <= 100; i++) Результат выполнения программы на 4-х ядерном процессоре будет следующим: Поток 0 получает право на выполнение итераций 1-25. Поток 1 получает право на выполнение итераций 26-50. Поток 2 получает право на выполнение итераций 51-75. Поток 3 получает право на выполнение итераций 76-100. 1 июля Москва, 2013 Технология параллельного программирования OpenMP 37 из 125 Распределение витков цикла. Клауза schedule


Слайд 37

#pragma omp parallel for schedule(static, 10) for(int i = 1; i <= 100; i++) Результат выполнения программы на 4-х ядерном процессоре будет следующим: Поток 0 получает право на выполнение итераций 1-10, 41-50, 81-90. Поток 1 получает право на выполнение итераций 11-20, 51-60, 91-100. Поток 2 получает право на выполнение итераций 21-30, 61-70. Поток 3 получает право на выполнение итераций 31-40, 71-80 1 июля Москва, 2013 Технология параллельного программирования OpenMP 38 из 125 Распределение витков цикла. Клауза schedule


Слайд 38

#pragma omp parallel for schedule(dynamic, 15) for(int i = 1; i <= 100; i++) Результат выполнения программы на 4-х ядерном процессоре может быть следующим: Поток 0 получает право на выполнение итераций 1-15. Поток 1 получает право на выполнение итераций 16-30. Поток 2 получает право на выполнение итераций 31-45. Поток 3 получает право на выполнение итераций 46-60. Поток 3 завершает выполнение итераций. Поток 3 получает право на выполнение итераций 61-75. Поток 2 завершает выполнение итераций. Поток 2 получает право на выполнение итераций 76-90. Поток 0 завершает выполнение итераций. Поток 0 получает право на выполнение итераций 91-100. 1 июля Москва, 2013 Технология параллельного программирования OpenMP 39 из 125 Распределение витков цикла. Клауза schedule


Слайд 39

число_выполняемых_потоком_итераций = max(число_нераспределенных_итераций/omp_get_num_threads(), число_итераций) #pragma omp parallel for schedule(guided, 10) for(int i = 1; i <= 100; i++) Пусть программа запущена на 4-х ядерном процессоре. Поток 0 получает право на выполнение итераций 1-25. Поток 1 получает право на выполнение итераций 26-44. Поток 2 получает право на выполнение итераций 45-59. Поток 3 получает право на выполнение итераций 60-69. Поток 3 завершает выполнение итераций. Поток 3 получает право на выполнение итераций 70-79. Поток 2 завершает выполнение итераций. Поток 2 получает право на выполнение итераций 80-89. Поток 3 завершает выполнение итераций. Поток 3 получает право на выполнение итераций 90-99. Поток 1 завершает выполнение итераций. Поток 1 получает право на выполнение 100 итерации. 1 июля Москва, 2013 Технология параллельного программирования OpenMP 40 из 125 Распределение витков цикла. Клауза schedule


Слайд 40

#pragma omp parallel for schedule(runtime) for(int i = 1; i <= 100; i++) /* способ распределения витков цикла между нитями будет задан во время выполнения программы*/ При помощи переменных среды: csh: setenv OMP_SCHEDULE "dynamic,4“ ksh: export OMP_SCHEDULE="static,10“ Windows: set OMP_SCHEDULE=auto или при помощи функции системы поддержки: void omp_set_schedule(omp_sched_t kind, int modifier); 1 июля Москва, 2013 Технология параллельного программирования OpenMP 41 из 125 Распределение витков цикла. Клауза schedule


Слайд 41

#pragma omp parallel for schedule(auto) for(int i = 1; i <= 100; i++) Способ распределения витков цикла между нитями определяется реализацией компилятора. На этапе компиляции программы или во время ее выполнения определяется оптимальный способ распределения. 1 июля Москва, 2013 Технология параллельного программирования OpenMP 42 из 125 Распределение витков цикла. Клауза schedule


Слайд 42

void example(int n, float *a, float *b, float *z) { int i; #pragma omp parallel { #pragma omp for schedule(static) nowait for (i=0; i<n; i++) c[i] = (a[i] + b[i]) / 2.0; #pragma omp for schedule(static) nowait for (i=0; i<n; i++) z[i] = sqrt(c[i]); } } Верно в OpenMP 3.0, если количество итераций у циклов совпадает и параметры клаузы schedule совпадают (STATIC + число_итераций). 1 июля Москва, 2013 Технология параллельного программирования OpenMP 43 из 125 Распределение витков цикла. Клауза nowait


Слайд 43

for(int i = 1; i < 100; i++) a[i]= a[i-1] + a[i+1] Между витками цикла с индексами i1 и i2 ( i1<i2 ) существует зависимость по данным (информационная связь) массива A, если оба эти витка осуществляют обращение к одному элементу массива по схеме запись-чтение или чтение-запись. Если виток i1 записывает значение, а виток i2 читает это значение, то между этими витками существует потоковая зависимость или просто зависимость i1 ->  i2. Если виток i1 читает "старое" значение, а виток i2 записывает "новое" значение, то между этими витками существует обратная зависимость i1<- i2. В обоих случаях виток i2 может выполняться только после витка i1. 1 июля Москва, 2013 Технология параллельного программирования OpenMP 44 из 125 Распределение циклов с зависимостью по данным


Слайд 44

void print_iteration(int iter) { #pragma omp ordered printf("iteration %d\n", iter); } int main( ) { int i; #pragma omp parallel { #pragma omp for ordered for (i = 0 ; i < 5 ; i++) { print_iteration(i); another_work (i); } } } 1 июля Москва, 2013 Технология параллельного программирования OpenMP 45 из 125 Распределение циклов с зависимостью по данным. Клауза и директива ordered Результат выполнения программы: iteration 0 iteration 1 iteration 2 iteration 3 iteration 4


Слайд 45

Цикл с зависимостью по данным может быть распараллелен с помощью клаузы ordered: #pragma omp parallel for ordered for(int i = 1; i < 100; i++) { #pragma omp ordered { a[i]= a[i-1] + a[i+1] } } 1 июля Москва, 2013 Технология параллельного программирования OpenMP 46 из 125 Распределение циклов с зависимостью по данным. Клауза и директива ordered


Слайд 46

for(int i = 1; i < M; i++) for(int j = 1; j < N; j++) a[i][j] = (a[i-1][j] + a[i][j-1] + a[i+1][j] + a[i][j+1]) / 4; 1 июля Москва, 2013 Технология параллельного программирования OpenMP 47 из 125 Распределение циклов с зависимостью по данным. Организация конвейерного выполнения цикла


Слайд 47

for(int i = 1; i < M; i++) for(int j = 1; j < N; j++) a[i][j] = (a[i-1][j] + a[i][j-1] + a[i+1][j] + a[i][j+1]) / 4; 1 июля Москва, 2013 Технология параллельного программирования OpenMP 48 из 125 Распределение циклов с зависимостью по данным. Организация конвейерного выполнения цикла


Слайд 48

1 июля Москва, 2013 Технология параллельного программирования OpenMP 49 из 125 Распределение циклов с зависимостью по данным. Организация конвейерного выполнения цикла


Слайд 49

1 июля Москва, 2013 Технология параллельного программирования OpenMP 50 из 125 Распределение циклов с зависимостью по данным. Организация конвейерного выполнения цикла #pragma omp parallel { int iam = omp_get_thread_num (); int numt = omp_get_num_threads (); for (int newi=1; newi<M + numt - 1; newi++) { int i = newi - iam; #pragma omp for for (int j=1; j<N; j++) { if (i >= 1) && (i< N)) { a[i][j]=(a[i-1][j] + a[i][j-1] + a[i+1][j] + a[i][j+1])/4; } } } }


Слайд 50

1 июля Москва, 2013 Технология параллельного программирования OpenMP 51 из 125 Распределение нескольких структурных блоков между нитями (директива sections)


Слайд 51

#pragma omp single [клауза[[,] клауза] ...] структурный блок где клауза одна из : private(list) firstprivate(list) copyprivate(list) nowait Структурный блок будет выполнен одной из нитей. Все остальные нити будут дожидаться результатов выполнения блока, если не указана клауза NOWAIT. 1 июля Москва, 2013 Технология параллельного программирования OpenMP 52 из 125 #include <stdio.h> static float x, y; #pragma omp threadprivate(x, y) void init(float *a, float *b ) { #pragma omp single copyprivate(a,b,x,y) scanf("%f %f %f %f", a, b, &x, &y); } int main () { #pragma omp parallel { float x1,y1; init (&x1,&y1); parallel_work (); } } Выполнение структурного блока одной нитью (директива single)


Слайд 52

1 июля Москва, 2013 Технология параллельного программирования OpenMP 53 из 125 Распределение операторов одного структурного блока между нитями (директива WORKSHARE) SUBROUTINE EXAMPLE (AA, BB, CC, DD, EE, FF, GG, HH, N) INTEGER N REAL AA(N,N), BB(N,N), CC(N,N) REAL DD(N,N), EE(N,N), FF(N,N) REAL GG(N,N), HH(N,N) REAL SHR !$OMP PARALLEL SHARED(SHR) !$OMP WORKSHARE AA = BB CC = DD WHERE (EE .ne. 0) FF = 1 / EE SHR = 1.0 GG (1:50,1) = HH(11:60,1) HH(1:10,1) = SHR !$OMP END WORKSHARE !$OMP END PARALLEL END SUBROUTINE EXAMPLE


Слайд 53

1 июля Москва, 2013 Технология параллельного программирования OpenMP 54 из 125 Понятие задачи Задачи появились в OpenMP 3.0 Каждая задача: Представляет собой последовательность операторов, которые необходимо выполнить. Включает в себя данные, которые используются при выполнении этих операторов. Выполняется некоторой нитью. В OpenMP 3.0 каждый оператор программы является частью одной из задач. При входе в параллельную область создаются неявные задачи (implicit task), по одной задаче для каждой нити. Создается группа нитей. Каждая нить из группы выполняет одну из задач. По завершении выполнения параллельной области, master-нить ожидает, пока не будут завершены все неявные задачи.


Слайд 54

1 июля Москва, 2013 Технология параллельного программирования OpenMP 55 из 125 Понятие задачи. Директива task Явные задачи (explicit tasks) задаются при помощи директивы: #pragma omp task [клауза[[,] клауза] ...] структурный блок где клауза одна из : if (scalar-expression) final(scalar-expression) //OpenMP 3.1 untied mergeable //OpenMP 3.1 shared (list) private (list) firstprivate (list) default( shared | none ) В результате выполнения директивы task создается новая задача, которая состоит из операторов структурного блока; все используемые в операторах переменные могут быть локализованы внутри задачи при помощи соответствующих клауз. Созданная задача будет выполнена одной нитью из группы.


Слайд 55

1 июля Москва, 2013 Технология параллельного программирования OpenMP 56 из 125 Понятие задачи. Директива task #pragma omp for schedule(dynamic) for (i=0; i<n; i++) { func(i); } #pragma omp single { for (i=0; i<n; i++) { #pragma omp task firstprivate(i) func(i); } }


Слайд 56

1 июля Москва, 2013 Технология параллельного программирования OpenMP 57 из 125 Использование директивы task typedef struct node node; struct node { int data; node * next; }; void increment_list_items(node * head) { #pragma omp parallel { #pragma omp single { node * p = head; while (p) { #pragma omp task process(p); p = p->next; } } } }


Слайд 57

1 июля Москва, 2013 Технология параллельного программирования OpenMP 58 из 125 Использование директивы task. Клауза if double *item; int main() { #pragma omp parallel shared (item) { #pragma omp single { int size; scanf("%d",&size); item = (double*)malloc(sizeof(double)*size); for (int i=0; i<size; i++) #pragma omp task if (size > 10) process(item[i]); } } } Если накладные расходы на организацию задач превосходят время, необходимое для выполнения блока операторов этой задачи, то блок операторов будет немедленно выполнен нитью, выполнившей директиву task


Слайд 58

1 июля Москва, 2013 Технология параллельного программирования OpenMP 59 из 125 Использование директивы task #define LARGE_NUMBER 10000000 double item[LARGE_NUMBER]; extern void process(double); int main() { #pragma omp parallel shared (item) { #pragma omp single { for (int i=0; i<LARGE_NUMBER; i++) #pragma omp task process(item[i]); } } } Как правило, в компиляторах существуют ограничения на количество создаваемых задач. Выполнение цикла, в котором создаются задачи, будет приостановлено. Нить, выполнявшая этот цикл, будет использована для выполнения одной из задач


Слайд 59

1 июля Москва, 2013 Технология параллельного программирования OpenMP 60 из 125 Использование директивы task. Клауза untied #define LARGE_NUMBER 10000000 double item[LARGE_NUMBER]; extern void process(double); int main() { #pragma omp parallel { #pragma omp single { #pragma omp task untied { for (int i=0; i<LARGE_NUMBER; i++) #pragma omp task process(item[i]); } } } } Клауза untied - выполнение задачи после приостановки может быть продолжено любой нитью группы


Слайд 60

1 июля Москва, 2013 Технология параллельного программирования OpenMP 61 из 125 Использование задач. Директива taskwait #pragma omp taskwait int fibonacci(int n) { int i, j; if (n<2) return n; else { #pragma omp task shared(i) i=fibonacci (n-1); #pragma omp task shared(j) j=fibonacci (n-2); #pragma omp taskwait return i+j; } } int main () { int res; #pragma omp parallel { #pragma omp single { int n; scanf("%d",&n); #pragma omp task shared(res) res = fibonacci(n); } } printf ("Finonacci number = %d\n", res); }


Слайд 61

1 июля Москва, 2013 Технология параллельного программирования OpenMP 62 из 125 Использование директивы task. Клауза final void fib (int n, int d) { int x, y; if (n < 2) return 1; #pragma omp task final (d > LIMIT) mergeable x = fib (n - 1, d + 1); #pragma omp task final (d > LIMIT) mergeable y = fib (n - 2, d + 1); #pragma omp taskwait return x + y; } int omp_in_final (void);


Слайд 62

1 июля Москва, 2013 Технология параллельного программирования OpenMP 63 из 125 OpenMP – модель параллелизма по управлению Конструкции распределения работы Конструкции для синхронизации нитей Система поддержки выполнения OpenMP-программ OpenMP 4.0 Содержание


Слайд 63

1 июля Москва, 2013 Технология параллельного программирования OpenMP 64 из 125 Директива master Директива critical Директива atomic Семафоры Директива barrier Директива taskwait Директива taskyield Конструкции для синхронизации нитей


Слайд 64

1 июля Москва, 2013 Технология параллельного программирования OpenMP 65 из 125 #pragma omp master структурный блок /*Структурный блок будет выполнен MASTER-нитью группы. По завершении выполнения структурного блока барьерная синхронизация нитей не выполняется*/ #include <stdio.h> void init(float *a, float *b ) { #pragma omp master scanf("%f %f", a, b); #pragma omp barrier } int main () { float x,y; #pragma omp parallel { init (&x,&y); parallel_work (x,y); } } Директива master


Слайд 65

1 июля Москва, 2013 Технология параллельного программирования OpenMP 66 из 125 #include <omp.h> int main () { int n =100000, i; double pi, h, sum, x; h = 1.0 / (double) n; sum = 0.0; #pragma omp parallel default (none) private (i,x) shared (n,h,sum) { double local_sum = 0.0; #pragma omp for nowait for (i = 1; i <= n; i++) { x = h * ((double)i - 0.5); local_sum += (4.0 / (1.0 + x*x)); } #pragma omp critical sum += local_sum; } pi = h * sum; printf("pi is approximately %.16f”, pi); return 0; } #pragma omp critical [(name)] структурный блок Вычисление числа ? на OpenMP с использованием критической секции


Слайд 66

Технология параллельного программирования OpenMP 67 из 125 #pragma omp atomic [ read | write | update | capture ] expression-stmt #pragma omp atomic capture structured-block Если указана клауза read: v = x; Если указана клауза write: x = expr; Если указана клауза update или клаузы нет, то expression-stmt: x binop= expr; x = x binop expr; x++; ++x; x--; --x; Директива atomic х – скалярная переменная, expr – выражение, в котором не присутствует переменная х. binop - не перегруженный оператор: + , * , - , / , & , ^ , | , << , >> binop=: ++ , -- 1 июля Москва, 2013


Слайд 67

Технология параллельного программирования OpenMP 68 из 125 Если указана клауза capture, то expression-stmt: v = x++; v = x--; v = ++x; v = -- x; v = x binop= expr; Если указана клауза capture, то structured-block: { v = x; x binop= expr;} { v = x; x = x binop expr;} { v = x; x++;} { v = x; ++x;} { v = x; x--;} { v = x; --x;} { x binop= expr; v = x;} { x = x binop expr; v = x;} { v = x; x binop= expr;} { x++; v = x;} { ++ x ; v = x;} { x--; v = x;} { --x; v = x;} Директива atomic


Слайд 68

Технология параллельного программирования OpenMP 69 из 125 type __sync_fetch_and_add (type *ptr, type value, ...) type __sync_fetch_and_sub (type *ptr, type value, ...) type __sync_fetch_and_or (type *ptr, type value, ...) type __sync_fetch_and_and (type *ptr, type value, ...) type __sync_fetch_and_xor (type *ptr, type value, ...) type __sync_fetch_and_nand (type *ptr, type value, ...) type __sync_add_and_fetch (type *ptr, type value, ...) type __sync_sub_and_fetch (type *ptr, type value, ...) type __sync_or_and_fetch (type *ptr, type value, ...) type __sync_and_and_fetch (type *ptr, type value, ...) type __sync_xor_and_fetch (type *ptr, type value, ...) type __sync_nand_and_fetch (type *ptr, type value, ...) bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...) type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...) http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html Встроенные функции для атомарного доступа к памяти в GCC 1 июля Москва, 2013


Слайд 69

1 июля Москва, 2013 Технология параллельного программирования OpenMP 70 из 125 int main () { int n =100000, i; double pi, h, sum, x; h = 1.0 / (double) n; sum = 0.0; #pragma omp parallel default (none) private (i,x) shared (n,h,sum) { double local_sum = 0.0; #pragma omp for for (i = 1; i <= n; i++) { x = h * ((double)i - 0.5); local_sum += (4.0 / (1.0 + x*x)); } #pragma omp atomic sum += local_sum; } pi = h * sum; printf("pi is approximately %.16f”, pi); return 0; } Вычисление числа ? на OpenMP с использованием директивы atomic


Слайд 70

1 июля Москва, 2013 Технология параллельного программирования OpenMP 71 из 125 int atomic_read(const int *p) { int value; /* Guarantee that the entire value of *p is read atomically. No part of * *p can change during the read operation. */ #pragma omp atomic read value = *p; return value; } void atomic_write(int *p, int value) { /* Guarantee that value is stored atomically into *p. No part of *p can change * until after the entire write operation is completed. */ #pragma omp atomic write *p = value; } Использование директивы atomic


Слайд 71

1 июля Москва, 2013 Технология параллельного программирования OpenMP 72 из 125 int fetch_and_add(int *p) { /* Atomically read the value of *p and then increment it. The previous value is * returned. */ int old; #pragma omp atomic capture { old = *p; (*p)++; } return old; } Использование директивы atomic


Слайд 72

1 июля Москва, 2013 Технология параллельного программирования OpenMP 73 из 125 Концепцию семафоров описал Дейкстра (Dijkstra) в 1965 Семафор - неотрицательная целая переменная, которая может изменяться и проверяться только посредством двух функций: P - функция запроса семафора P(s): [if (s == 0) <заблокировать текущий процесс>; else s = s-1;] V - функция освобождения семафора V(s): [if (s == 0) <разблокировать один из заблокированных процессов>; s = s+1;] Семафоры


Слайд 73

1 июля Москва, 2013 Технология параллельного программирования OpenMP 74 из 125 Состояния семафора: uninitialized unlocked locked void omp_init_lock(omp_lock_t *lock); /* uninitialized to unlocked*/ void omp_destroy_lock(omp_lock_t *lock); /* unlocked to uninitialized */ void omp_set_lock(omp_lock_t *lock); /*P(lock)*/ void omp_unset_lock(omp_lock_t *lock); /*V(lock)*/ int omp_test_lock(omp_lock_t *lock); void omp_init_nest_lock(omp_nest_lock_t *lock); void omp_destroy_nest_lock(omp_nest_lock_t *lock); void omp_set_nest_lock(omp_nest_lock_t *lock); void omp_unset_nest_lock(omp_nest_lock_t *lock); int omp_test_nest_lock(omp_nest_lock_t *lock); Семафоры в OpenMP


Слайд 74

1 июля Москва, 2013 Технология параллельного программирования OpenMP 75 из 125 int main () { int n =100000, i; double pi, h, sum, x; omp_lock_t lck; h = 1.0 / (double) n; sum = 0.0; omp_init_lock(&lck); #pragma omp parallel default (none) private (i,x) shared (n,h,sum,lck) { double local_sum = 0.0; #pragma omp for nowait for (i = 1; i <= n; i++) { x = h * ((double)i - 0.5); local_sum += (4.0 / (1.0 + x*x)); } omp_set_lock(&lck); sum += local_sum; omp_unset_lock(&lck); } pi = h * sum; printf("pi is approximately %.16f", pi); omp_destroy_lock(&lck); return 0; } Вычисление числа ? c использованием семафоров


Слайд 75

1 июля Москва, 2013 Технология параллельного программирования OpenMP 76 из 125 #include <stdio.h> #include <omp.h> int main() { omp_lock_t lck; int id; omp_init_lock(&lck); #pragma omp parallel shared(lck) private(id) { id = omp_get_thread_num(); omp_set_lock(&lck); printf("My thread id is %d.\n", id); /* only one thread at a time can execute this printf */ omp_unset_lock(&lck); while (! omp_test_lock(&lck)) { skip(id); /* we do not yet have the lock, so we must do something else*/ } work(id); /* we now have the lock and can do the work */ omp_unset_lock(&lck); } omp_destroy_lock(&lck); return 0; } Использование семафоров void skip(int i) {} void work(int i) {}


Слайд 76

1 июля Москва, 2013 Технология параллельного программирования OpenMP 77 из 125 Использование семафоров #include <omp.h> typedef struct { int a,b; omp_lock_t lck; } pair; void incr_a(pair *p, int a) { p->a += a; } void incr_b(pair *p, int b) { omp_set_lock(&p->lck); p->b += b; omp_unset_lock(&p->lck); } void incr_pair(pair *p, int a, int b) { omp_set_lock(&p->lck); incr_a(p, a); incr_b(p, b); omp_unset_lock(&p->lck); } void incorrect_example(pair *p) { #pragma omp parallel sections { #pragma omp section incr_pair(p,1,2); #pragma omp section incr_b(p,3); } } Deadlock!


Слайд 77

1 июля Москва, 2013 Технология параллельного программирования OpenMP 78 из 125 Использование семафоров #include <omp.h> typedef struct { int a,b; omp_nest_lock_t lck; } pair; void incr_a(pair *p, int a) { p->a += a; } void incr_b(pair *p, int b) { omp_nest_set_lock(&p->lck); p->b += b; omp_nest_unset_lock(&p->lck); } void incr_pair(pair *p, int a, int b) { omp_nest_set_lock(&p->lck); incr_a(p, a); incr_b(p, b); omp_nest_unset_lock(&p->lck); } void incorrect_example(pair *p) { #pragma omp parallel sections { #pragma omp section incr_pair(p,1,2); #pragma omp section incr_b(p,3); } }


Слайд 78

1 июля Москва, 2013 Технология параллельного программирования OpenMP 79 из 125 #include <omp.h> void something_useful ( void ); void something_critical ( void ); void foo ( omp_lock_t * lock, int n ) { int i; for ( i = 0; i < n; i++ ) #pragma omp task { something_useful(); while ( !omp_test_lock(lock) ) { #pragma omp taskyield } something_critical(); omp_unset_lock(lock); } } Директива taskyield


Слайд 79

1 июля Москва, 2013 Технология параллельного программирования OpenMP 80 из 125 Точка в программе, достижимая всеми нитями группы, в которой выполнение программы приостанавливается до тех пор пока все нити группы не достигнут данной точки и все задачи, выполняемые группой нитей будут завершены. #pragma omp barrier По умолчанию барьерная синхронизация нитей выполняется: по завершению конструкции parallel; при выходе из конструкций распределения работ (for, single, sections, workshare) , если не указана клауза nowait. #pragma omp parallel { #pragma omp master { int i, size; scanf("%d",&size); for (i=0; i<size; i++) { #pragma omp task process(i); } } #pragma omp barrier } Директива barrier


Слайд 80

1 июля Москва, 2013 Технология параллельного программирования OpenMP 81 из 125 OpenMP – модель параллелизма по управлению Конструкции распределения работы Конструкции для синхронизации нитей Система поддержки выполнения OpenMP-программ OpenMP 4.0 Содержание


Слайд 81

1 июля Москва, 2013 Технология параллельного программирования OpenMP 82 из 125 Внутренние переменные, управляющие выполнением OpenMP-программы (ICV-Internal Control Variables) Для параллельных областей: nthreads-var thread-limit-var dyn-var nest-var max-active-levels-var Для циклов: run-sched-var def-sched-var Для всей программы: stacksize-var wait-policy-var bind-var


Слайд 82

1 июля Москва, 2013 Технология параллельного программирования OpenMP 83 из 125 Internal Control Variables. nthreads-var void work(); int main () { omp_set_num_threads(3); #pragma omp parallel { omp_set_num_threads(omp_get_thread_num ()+2); #pragma omp parallel work(); } } Существует одна копия этой переменной для каждой задачи Не корректно в OpenMP 2.5 Корректно в OpenMP 3.0


Слайд 83

1 июля Москва, 2013 Технология параллельного программирования OpenMP 84 из 125 Определяет максимально возможное количество нитей в создаваемой параллельной области. Начальное значение: зависит от реализации. Существует одна копия этой переменной для каждой задачи. Значение переменной можно изменить: C shell: setenv OMP_NUM_THREADS 4,3,2 Korn shell: export OMP_NUM_THREADS=16 Windows: set OMP_NUM_THREADS=16 void omp_set_num_threads(int num_threads); Узнать значение переменной можно: int omp_get_max_threads(void); Internal Control Variables. nthreads-var


Слайд 84

1 июля Москва, 2013 Технология параллельного программирования OpenMP 85 из 125 Определяет максимальное количество нитей, которые могут быть использованы для выполнения всей программы. Начальное значение: зависит от реализации. Существует одна копия этой переменной для всей программы. Значение переменной можно изменить: C shell: setenv OMP_THREAD_LIMIT 16 Korn shell: export OMP_THREAD_LIMIT=16 Windows: set OMP_THREAD_LIMIT=16 Узнать значение переменной можно: int omp_get_thread_limit(void) Internal Control Variables. thread-limit-var


Слайд 85

1 июля Москва, 2013 Технология параллельного программирования OpenMP 86 из 125 Включает/отключает режим, в котором количество создаваемых нитей при входе в параллельную область может меняться динамически. Начальное значение: Если компилятор не поддерживает данный режим, то false. Существует одна копия этой переменной для каждой задачи. Значение переменной можно изменить: C shell: setenv OMP_DYNAMIC true Korn shell: export OMP_DYNAMIC=true Windows: set OMP_DYNAMIC=true void omp_set_dynamic(int dynamic_threads); Узнать значение переменной можно: int omp_get_dynamic(void); Internal Control Variables. dyn-var


Слайд 86

1 июля Москва, 2013 Технология параллельного программирования OpenMP 87 из 125 Включает/отключает режим поддержки вложенного параллелизма. Начальное значение: false. Существует одна копия этой переменной для каждой задачи. Значение переменной можно изменить: C shell: setenv OMP_NESTED true Korn shell: export OMP_NESTED=false Windows: set OMP_NESTED=true void omp_set_nested(int nested); Узнать значение переменной можно: int omp_get_nested(void); Internal Control Variables. nest-var


Слайд 87

1 июля Москва, 2013 Технология параллельного программирования OpenMP 88 из 125 Задает максимально возможное количество активных вложенных параллельных областей. Начальное значение: зависит от реализации. Существует одна копия этой переменной для всей программы. Значение переменной можно изменить: C shell: setenv OMP_MAX_ACTIVE_LEVELS 2 Korn shell: export OMP_MAX_ACTIVE_LEVELS=3 Windows: set OMP_MAX_ACTIVE_LEVELS=4 void omp_set_max_active_levels (int max_levels); Узнать значение переменной можно: int omp_get_max_active_levels(void); Internal Control Variables. max-active-levels-var


Слайд 88

1 июля Москва, 2013 Технология параллельного программирования OpenMP 89 из 125 Задает способ распределения витков цикла между нитями, если указана клауза schedule(runtime). Начальное значение: зависит от реализации. Существует одна копия этой переменной для каждой задачи. Значение переменной можно изменить: C shell: setenv OMP_SCHEDULE "guided,4" Korn shell: export OMP_SCHEDULE "dynamic,5" Windows: set OMP_SCHEDULE=static void omp_set_schedule(omp_sched_t kind, int modifier); Узнать значение переменной можно: void omp_get_schedule(omp_sched_t * kind, int * modifier ); typedef enum omp_sched_t { omp_sched_static = 1, omp_sched_dynamic = 2, omp_sched_guided = 3, omp_sched_auto = 4 } omp_sched_t; Internal Control Variables. run-sched-var


Слайд 89

1 июля Москва, 2013 Технология параллельного программирования OpenMP 90 из 125 Задает способ распределения витков цикла между нитями по умолчанию. Начальное значение: зависит от реализации. Существует одна копия этой переменной для всей программы. void work(int i); int main () { #pragma omp parallel { #pragma omp for for (int i=0;i<N;i++) work (i); } } Internal Control Variables. def-sched-var


Слайд 90

1 июля Москва, 2013 Технология параллельного программирования OpenMP 91 из 125 Каждая нить представляет собой независимо выполняющийся поток управления со своим счетчиком команд, регистровым контекстом и стеком. Переменная stack-size-var задает размер стека. Начальное значение: зависит от реализации. Существует одна копия этой переменной для всей программы. Значение переменной можно изменить: setenv OMP_STACKSIZE 2000500B setenv OMP_STACKSIZE "3000 k" setenv OMP_STACKSIZE 10M setenv OMP_STACKSIZE "10 M" setenv OMP_STACKSIZE "20 m" setenv OMP_STACKSIZE "1G" setenv OMP_STACKSIZE 20000 Internal Control Variables. stack-size-var


Слайд 91

1 июля Москва, 2013 Технология параллельного программирования OpenMP 92 из 125 int main () { int a[1024][1024]; #pragma omp parallel private (a) { for (int i=0;i<1024;i++) for (int j=0;j<1024;j++) a[i][j]=i+j; } } icl /Qopenmp test.cpp Program Exception – stack overflow Linux: ulimit -a ulimit -s <stacksize in Кbytes> Windows: /F<stacksize in bytes> -Wl,--stack, <stacksize in bytes> setenv KMP_STACKSIZE 10m setenv GOMP_STACKSIZE 10000 setenv OMP_STACKSIZE 10M Internal Control Variables. stack-size-var


Слайд 92

1 июля Москва, 2013 Технология параллельного программирования OpenMP 93 из 125 Подсказка OpenMP-компилятору о желаемом поведении нитей во время ожидания. Начальное значение: зависит от реализации. Существует одна копия этой переменной для всей программы. Значение переменной можно изменить: setenv OMP_WAIT_POLICY ACTIVE setenv OMP_WAIT_POLICY active setenv OMP_WAIT_POLICY PASSIVE setenv OMP_WAIT_POLICY passive IBM AIX SPINLOOPTIME=100000 YIELDLOOPTIME=40000 Internal Control Variables. wait-policy-var


Слайд 93

1 июля Москва, 2013 Технология параллельного программирования OpenMP 94 из 125 Internal Control Variables. Приоритеты


Слайд 94

1 июля Москва, 2013 Технология параллельного программирования OpenMP 95 из 125 int omp_get_num_threads(void); -возвращает количество нитей в текущей параллельной области #include <omp.h> void work(int i); void test() { int np; np = omp_get_num_threads(); /* np == 1*/ #pragma omp parallel private (np) { np = omp_get_num_threads(); #pragma omp for schedule(static) for (int i=0; i < np; i++) work(i); } } Система поддержки выполнения OpenMP-программ


Слайд 95

1 июля Москва, 2013 Технология параллельного программирования OpenMP 96 из 125 int omp_get_thread_num(void); -возвращает номер нити в группе [0: omp_get_num_threads()-1] #include <omp.h> void work(int i); void test() { int iam; iam = omp_get_thread_num(); /* iam == 0*/ #pragma omp parallel private (iam) { iam = omp_get_thread_num(); work(iam); } } Система поддержки выполнения OpenMP-программ


Слайд 96

1 июля Москва, 2013 Технология параллельного программирования OpenMP 97 из 125 int omp_get_num_procs(void); -возвращает количество процессоров, на которых программа выполняется #include <omp.h> void work(int i); void test() { int nproc; nproc = omp_get_num_ procs(); #pragma omp parallel num_threads(nproc) { int iam = omp_get_thread_num(); work(iam); } } Система поддержки выполнения OpenMP-программ


Слайд 97

1 июля Москва, 2013 Технология параллельного программирования OpenMP 98 из 125 int omp_get_level(void) - возвращает уровень вложенности для текущей параллельной области. #include <omp.h> void work(int i) { #pragma omp parallel { int ilevel = omp_get_level (); } } void test() { int ilevel = omp_get_level (); /*ilevel==0*/ #pragma omp parallel private (ilevel) { ilevel = omp_get_level (); int iam = omp_get_thread_num(); work(iam); } } Система поддержки выполнения OpenMP-программ


Слайд 98

1 июля Москва, 2013 Технология параллельного программирования OpenMP 99 из 125 int omp_get_active_level(void) - возвращает количество активных параллельных областей (выполняемых 2-мя или более нитями). #include <omp.h> void work(int iam, int size) { #pragma omp parallel { int ilevel = omp_get_active_level (); } } void test() { int size = 0; int ilevel = omp_get_active_level (); /*ilevel==0*/ scanf("%d",&size); #pragma omp parallel if (size>10) { int iam = omp_get_thread_num(); work(iam, size); } } Система поддержки выполнения OpenMP-программ


Слайд 99

1 июля Москва, 2013 Технология параллельного программирования OpenMP 100 из 125 int omp_get_ancestor_thread_num (int level) - для нити, вызвавшей данную функцию, возвращается номер нити-родителя, которая создала указанную параллельную область. omp_get_ancestor_thread_num (0) = 0 If (level==omp_get_level()) { omp_get_ancestor_thread_num (level) == omp_get_thread_num (); } If ((level<0)||(level>omp_get_level())) { omp_get_ancestor_thread_num (level) == -1; } Система поддержки выполнения OpenMP-программ


Слайд 100

1 июля Москва, 2013 Технология параллельного программирования OpenMP 101 из 125 int omp_get_team_size(int level); - количество нитей в указанной параллельной области. omp_get_team_size (0) = 1 If (level==omp_get_level()) { omp_get_team_size (level) == omp_get_num _threads (); } If ((level<0)||(level>omp_get_level())) { omp_get_team_size (level) == -1; } Система поддержки выполнения OpenMP-программ


Слайд 101

1 июля Москва, 2013 Технология параллельного программирования OpenMP 102 из 125 double omp_get_wtime(void); возвращает для нити астрономическое время в секундах, прошедшее с некоторого момента в прошлом. Если некоторый участок окружить вызовами данной функции, то разность возвращаемых значений покажет время работы данного участка. Гарантируется, что момент времени, используемый в качестве точки отсчета, не будет изменен за время выполнения программы. double start; double end; start = omp_get_wtime(); /*... work to be timed ...*/ end = omp_get_wtime(); printf("Work took %f seconds\n", end - start); double omp_get_wtick(void); - возвращает разрешение таймера в секундах (количество секунд между последовательными импульсами таймера). Система поддержки выполнения OpenMP-программ. Функции работы со временем


Слайд 102

1 июля Москва, 2013 Технология параллельного программирования OpenMP 103 из 125 OpenMP – модель параллелизма по управлению Конструкции распределения работы Конструкции для синхронизации нитей Система поддержки выполнения OpenMP-программ OpenMP 4.0 Содержание


Слайд 103

1 июля Москва, 2013 Технология параллельного программирования OpenMP 104 из 125 #pragma omp declare reduction (reduction-identifier : typename-list : combiner) [identity(identity-expr)] reduction-identifier gives a name to the operator typename-list is a list of types to which it applies combiner expression specifies how to combine values identity can specify the identity value of the operator Редукционные операции, определяемые пользователем


Слайд 104

1 июля Москва, 2013 Технология параллельного программирования OpenMP 105 из 125 #pragma omp declare reduction (merge : std::vector<int> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end())) void schedule (std::vector<int> &v, std::vector<int> &filtered) { #pragma omp parallel for reduction (merge: filtered) for (std:vector<int>::iterator it = v.begin(); it < v.end(); it++) if ( filter(*it) ) filtered.push_back(*it); } omp_out refers to private copy that holds combined value omp_in refers to the other private copy Редукционные операции, определяемые пользователем


Слайд 105

1 июля Москва, 2013 Технология параллельного программирования OpenMP 106 из 125 Клауза depend(dependence-type : list) где dependence-type: in out inout int i, y, a[100]; #pragma omp task depend(out : a) { for (i=0;i<100; i++) a[i] = i + 1; } #pragma omp task depend(in : a[0:49]) depend(out : y) { y = 0; for (i=0;i<50; i++) y += a[i]; } #pragma omp task depend(in : y) { printf(“%d\n”, y); } Task Dependencies


Слайд 106

1 июля Москва, 2013 Технология параллельного программирования OpenMP 107 из 125 Директива #pragma omp cancel clause[[,] clause ] где clause одна из: parallel sections for taskgroup if (scalar-expression) Директива #pragma omp cancellation point clause[[,] clause ] где clause одна из: parallel sections for taskgroup Cancellation Constructs


Слайд 107

1 июля Москва, 2013 Технология параллельного программирования OpenMP 108 из 125 #pragma omp simd [clause[[,] clause]..] for-loops #pragma omp declare simd [clause[[,] clause]..] function definition or declaration #pragma omp for simd [clause[[,] clause]..] for-loops SIMD Contstructs


Слайд 108

1 июля Москва, 2013 Технология параллельного программирования OpenMP 109 из 125 export OMP_PLACES 0,1,2,3,8,10,12,14 Can also specify lists, groupings Planning new runtime library routines to observe and to control bindings (get_place, get/set_place_partition) Considering environment variables to: Control thread placement within a processor set Control initial placement of shared data Adapt data placement at runtime Привязка нитей к ядрам


Слайд 109

1 июля Москва, 2013 Технология параллельного программирования OpenMP 110 из 125 Расширение OpenMP для использования ускорителей … Node 1 Node 64


Слайд 110

1 июля Москва, 2013 Технология параллельного программирования OpenMP 111 из 125 Алгоритм Якоби на языке Fortran PROGRAM JACOB_SEQ PARAMETER (L=4096, ITMAX=100) REAL A(L,L), B(L,L)   PRINT *, '********** TEST_JACOBI **********' DO IT = 1, ITMAX DO J = 2, L-1 DO I = 2, L-1 A(I, J) = B(I, J) ENDDO ENDDO   DO J = 2, L-1 DO I = 2, L-1 B(I, J) = (A(I-1, J) + A(I, J-1) + A(I+1, J) + * A(I, J+1)) / 4 ENDDO ENDDO ENDDO END


Слайд 111

1 июля Москва, 2013 Технология параллельного программирования OpenMP 112 из 125 Алгоритм Якоби на языке Fortran Cuda PROGRAM JACOB_CUDA use cudafor use jac_cuda PARAMETER (L=4096, ITMAX=100) parameter (block_dim = 16) real, device, dimension(l, l) :: a, b type(dim3) :: grid, block PRINT *, '***** TEST_JACOBI *******’ grid = dim3(l / block_dim, l / block_dim, 1) block = dim3(block_dim, block_dim, 1) DO IT = 1, ITMAX call arr_copy<<<grid, block>>>(a, b, l) call arr_renew<<<grid, block>>>(a, b, l) ENDDO END


Слайд 112

1 июля Москва, 2013 Технология параллельного программирования OpenMP 113 из 125 Алгоритм Якоби на языке Fortran Cuda module jac_cuda contains attributes(global) subroutine arr_copy(a, b, k) real, device, dimension(k, k) :: a, b integer, value :: k integer i, j i = (blockIdx%x - 1) * blockDim%x + threadIdx%x j = (blockIdx%y - 1) * blockDim%y + threadIdx%y if (i.ne.1 .and. i.ne.k .and. j.ne.1 .and. j.ne.k) A(I, J) = B(I, J) end subroutine arr_copy attributes(global) subroutine arr_renew(a, b, k) real, device, dimension(k, k) :: a, b integer, value :: k integer i, j i = (blockIdx%x - 1) * blockDim%x + threadIdx%x j = (blockIdx%y - 1) * blockDim%y + threadIdx%y if (i.ne.1 .and. i.ne.k .and. j.ne.1 .and. j.ne.k) B(I,J) =(A( I-1,J)+A(I,J-1)+A(I+1,J)+ A(I,J+1))/4 end subroutine arr_renew end module jac_cuda


Слайд 113

1 июля Москва, 2013 Технология параллельного программирования OpenMP 114 из 125 Алгоритм Якоби в модели HMPP !$HMPP jacoby codelet, target = CUDA SUBROUTINE JACOBY(A,B,L) IMPLICIT NONE INTEGER, INTENT(IN) :: L REAL, INTENT(IN) :: A(L,L) REAL, INTENT(INOUT) :: B(L,L) INTEGER I,J DO J = 2, L-1 DO I = 2, L-1 A(I,J) = B(I,J) ENDDO ENDDO DO J = 2, L-1 DO I = 2, L-1 B(I,J) = (A(I-1,J ) + A(I,J-1 ) + * A(I+1,J ) + A(I,J+1 )) / 4 ENDDO ENDDO END SUBROUTINE JACOBY PROGRAM JACOBY_HMPP PARAMETER (L=4096, ITMAX=100) REAL A(L,L), B(L,L) PRINT *, '**********TEST_JACOBI**********‘ DO IT = 1, ITMAX !$HMPP jacoby callsite CALL JACOBY(A,B,L) ENDDO PRINT *, B END


Слайд 114

1 июля Москва, 2013 Технология параллельного программирования OpenMP 115 из 125 Алгоритм Якоби в модели HMPP PROGRAM JACOBY_HMPP PARAMETER (L=4096, ITMAX=100) REAL A(L,L), B(L,L) !$hmpp jac allocate, args[A;B].size={L,L} !$hmpp jac advancedload, args[B] PRINT *, '********** TEST_JACOBI **********' DO IT = 1, ITMAX !$hmpp jac region, args[A;B].noupdate=true DO J = 2, L-1 DO I = 2, L-1 A(I, J) = B(I, J) ENDDO ENDDO DO J = 2, L-1 DO I = 2, L-1 B(I, J)=(A(I-1,J)+A(I,J-1)+A(I+1,J) + * A(I, J+1)) / 4 ENDDO ENDDO !$hmpp jac endregion ENDDO !$hmpp jac delegatedstore, args[B] !$hmpp jac release PRINT *,B END


Слайд 115

1 июля Москва, 2013 Технология параллельного программирования OpenMP 116 из 125 Алгоритм Якоби в модели PGI APM PROGRAM JACOBY_PGI_APM PARAMETER (L=4096, ITMAX=100) REAL A(L,L), B(L,L) PRINT *, '********** TEST_JACOBI **********' !$acc data region copyin(B), copyout(B), local(A) DO IT = 1, ITMAX !$acc region DO J = 2, L-1 DO I = 2, L-1 A(I,J) = B(I,J) ENDDO ENDDO DO J = 2, L-1 DO I = 2, L-1 B(I,J) = (A(I-1,J ) + A(I,J-1 ) + A(I+1,J ) + A(I,J+1 )) / 4 ENDDO ENDDO !$acc end region ENDDO !$acc end data region PRINT *, B END


Слайд 116

1 июля Москва, 2013 Технология параллельного программирования OpenMP 117 из 125 Cray Compiling Environment 7.4.0 !$omp acc_region !$omp acc_loop DO j = 1,M DO i = 2,N c(i,j) = a(i,j) + b(i,j) ENDDO ENDDO !$omp end acc_loop !$omp end acc_region acc_region: acc_copy, acc_copyin, acc_copyout, acc_shared, private, firstprivate, default(<any of above>|none), present, if(scalar-logical-expression), device(integer-expression), num_pes(depth:num [, depth:num]), async(handle) acc_loop: reduction(operator:list), collapse(n), schedule, cache(obj[:depth], hetero…


Слайд 117

1 июля Москва, 2013 Технология параллельного программирования OpenMP 118 из 125 OpenACC #pragma acc data copy(A), create(Anew) while (iter<iter_max) { #pragma acc kernels loop for (int j = 1; j < n-1; j++) { for (int I = 1; I < m-1; i++) { Anew[j][i] = 0.25* (A[j][i+1] + A[j][i-1] +A[j-1][i] + A[j+1][i]); } } #pragma acc kernels loop for (int j = 1; j < n-1; j++) { for (int I = 1; i< m-1;i++ ) { A[j][i] = Anew[j][i]; } } iter++; }


Слайд 118

1 июля Москва, 2013 Технология параллельного программирования OpenMP 119 из 125 Intel Many Integrated Core (MIC) !dir$ offload target(mic) !$omp parallel do do i=1,10 A(i) = B(i) * C(i) enddo !$omp end parallel


Слайд 119

1 июля Москва, 2013 Технология параллельного программирования OpenMP 120 из 125 OpenMP accelerator model Новые директивы target target data target update target mirror target linkable Новые функции системы поддержки omp_get_device_num omp_set_device_num Новая переменная окружения OMP_DEVICE_NUM


Слайд 120

1 июля Москва, 2013 Технология параллельного программирования OpenMP 121 из 125 OpenMP accelerator model. Директива target #pragma omp target [clause[[,] clause ]] parallel-loop-construct | parallel-sections-construct где clause одна из: device(integer-expression) map ([map-type]:list) map-type: alloc to from if (scalar-expression) sum=0; #pragma omp target device(acc0) map(A,B) #pragma omp parallel for reduction(+: sum) for (i=0;i<N;i++) sum += A[i]*B[i];


Слайд 121

1 июля Москва, 2013 Технология параллельного программирования OpenMP 122 из 125 OpenMP accelerator model #pragma omp target data [clause[[,] clause ]] structured-block где clause одна из: device(integer-expression) map ([map-type]:list) map-type: alloc to from if (scalar-expression) #pragma omp target update[clause[[,] clause ]] где clause одна из: to (list) from (list) device(integer-expression) if (scalar-expression)


Слайд 122

1 июля Москва, 2013 Технология параллельного программирования OpenMP 123 из 125 OpenMP accelerator model. Директива declare target #pragma omp declare target function-defenition-or-declaration #pragma omp declare target void F(restrict float Q[][COLS], const int i, const k) { return Q[i][k]*Q[i][k]; } … #pragma omp target data map(Q[0:rows][0:cols]) #pragma omp parallel for reduction(+:sum) for(int i=0; i<rows;i++) sum+=F(Q,i,k);


Слайд 123

1 июля Москва, 2013 Технология параллельного программирования OpenMP 124 из 125 OpenMP Application Program Interface Version 3.1, July 2011. http://ww.openmp.org/mp-documents/OpenMP3.1.pdf Антонов А.С. Параллельное программирование с использованием технологии OpenMP: Учебное пособие.-М.: Изд-во МГУ, 2009. http://parallel.ru/info/parallel/openmp/OpenMP.pdf Э. Таненбаум, М. ван Стеен. Распределенные системы. Принципы и парадигмы. – СПб. Питер, 2003 Воеводин В.В., Воеводин Вл.В. Параллельные вычисления. – СПб.: БХВ-Петербург, 2002. Презентация ftp://ftp.keldysh.ru/K_student/MSU2013/Academy2013_OpenMP2.ppt Литература


Слайд 124

1 июля Москва, 2013 Технология параллельного программирования OpenMP 125 из 125 Бахтин Владимир Александрович, кандидат физико-математических наук, заведующий сектором Института прикладной математики им. М.В. Келдыша РАН, ассистент кафедры системного программирования факультета вычислительной математики и кибернетики Московского университета им. М.В. Ломоносова bakhtin@keldysh.ru Автор


×

HTML:





Ссылка: