Содержание

Слайд 2

Различие между тредами и процессами

Процессы

Треды

Различие между тредами и процессами Процессы Треды

Слайд 3

Общие и распределенные данные

var

var

var

распределенные

общие

Общие и распределенные данные var var var распределенные общие

Слайд 4

Архитектура OpenMP

Приложение

OpenMP
компилятор

OpenMP библиотека

Треды ОС

Пользователь

Переменные
среды

Архитектура OpenMP Приложение OpenMP компилятор OpenMP библиотека Треды ОС Пользователь Переменные среды

Слайд 5

Модель выполнения OpenMP приложения

Модель выполнения OpenMP приложения

Слайд 6

Работа с вычислительным пространством – число тредов

Мастер-тред имеет номер 0
Число

Работа с вычислительным пространством – число тредов Мастер-тред имеет номер 0 Число
тредов, выполняющих работу определяется:
- переменная окружения OMP_NUM_THREADS
- вызов функции omp_set_num_threads() (может вызываться перед параллельным участком, но не внутри этого участка)
Определение числа процессоров в системе: omp_get_num_procs()

Слайд 7

Работа с вычислительным пространством – динамическое определение числа тредов

В некоторых случаях целесообразно

Работа с вычислительным пространством – динамическое определение числа тредов В некоторых случаях
устанавливать число тредов динамически в зависимости от загрузки имеющихся процессоров.
Включить данную опцию можно с помощью переменной среды
OMP_DYNAMIC [TRUE, FALSE]
или с помощью функции omp_set_dynamic(int flag) (может вызываться перед параллельным участком, но не внутри этого участка)
Если flag != 0 , то механизм включается, в противном случае – выключается.

Слайд 8

Определение числа процессоров, тредов и своих координат в системе

int omp_get_num_procs() возвращает количество

Определение числа процессоров, тредов и своих координат в системе int omp_get_num_procs() возвращает
процессоров в системе;
int omp_get_num_threads() возвращает количество тредов, выполняющих параллельный участок (меняется только на последовательных участках);
int omp_get_thread_num() возвращает номер вызывающего треда.

Слайд 9

#include #include #include
main(int argc, char* argv[]) { omp_set_num_threads(atoi(argv[1])); printf("Total number of processors

#include #include #include main(int argc, char* argv[]) { omp_set_num_threads(atoi(argv[1])); printf("Total number of
is %d\n", omp_get_num_procs());
#pragma omp parallel printf("Hello, World from thread %d of %d\n", omp_get_thread_num(), omp_get_num_threads()); }

Слайд 10

Общий синтаксис директив OpenMP

#pragma omp directive_name [clause[clause ...]] newline
Действия, соответствующие директиве применяются

Общий синтаксис директив OpenMP #pragma omp directive_name [clause[clause ...]] newline Действия, соответствующие

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

Слайд 11

Директива parallel

Данная директива – единственный способ инициировать
параллельное выполнение программы.
#pragma omp parallel [clause

Директива parallel Данная директива – единственный способ инициировать параллельное выполнение программы. #pragma
...]
clause: if (scalar_expression)
private (list)
shared (list)
default (shared | none)
firstprivate (list)
reduction (operator: list)
copyin (list)

Слайд 12

#include
main () {
int nthreads, tid;
#pragma omp parallel private(nthreads, tid)
{
tid

#include main () { int nthreads, tid; #pragma omp parallel private(nthreads, tid)
= omp_get_thread_num();
printf("Hello World from thread = %d\n", tid);
if (tid == 0)
{
nthreads = omp_get_num_threads();
printf("Number of threads = %d\n", nthreads);
}
}
}

Слайд 13

Опции для данных

Данные, видимые в области, объемлющей блок параллельного
исполнения, являются общими (shared).

Опции для данных Данные, видимые в области, объемлющей блок параллельного исполнения, являются
Переменные,
объявленные внутри блока п.и. считаются распределенными
(private).
Опция private задает список распределенных переменных.
Только shared-переменные в объемлющей параллельном блоке могут быть аргументами опции private

Опция private

Слайд 14

Опция firstprivate обладает той же семантикой, что и
опция private. При этом,

Опция firstprivate обладает той же семантикой, что и опция private. При этом,
все копии переменной инициализируются значением исходной переменной до входа в блок на мастер-треде.

Опция firstprivate

М

Слайд 15

Опция default

Опция default задает опцию по-умолчанию для
переменных. Пример:
#pragma omp parallel default(private)

Опция shared

Опция

Опция default Опция default задает опцию по-умолчанию для переменных. Пример: #pragma omp
shared задает список общих переменных.
#pragma omp parallel default(private) shared(x)

Слайд 16

опция reduction

Опция reduction определяет что на выходе из параллельного блока переменная получит

опция reduction Опция reduction определяет что на выходе из параллельного блока переменная
комбинированное значение. Пример:
#pragma omp for reduction(+ : x)
Допустимы следующие операции: +, *, -, &, |, ^, &&, ||

Слайд 17

Глобальные общие данные

Проблема: опция private «работает» только для статически-видимых ссылок в пределах

Глобальные общие данные Проблема: опция private «работает» только для статически-видимых ссылок в
параллельного участка:
static int a;
f() { printf(“%d\n”, a); }
main() { #omp parallel private (a) { a = omp_num_thread(); f(); } }

значение a неопределено

Слайд 18

Директива threadprivate

#omp threadprivate (список глобальных переменных)
переменные становятся общими для всех тредов:
static int

Директива threadprivate #omp threadprivate (список глобальных переменных) переменные становятся общими для всех
a;
f() { printf(“%d\n”, a); }
main() { #omp threadprivate(a)
#omp parallel { a = omp_num_thread(); f(); } }

Слайд 19

Опция copyin

Опция copyin директивы parallel определяет порядок инициализации threadprivate-переменных: эти переменные

Опция copyin Опция copyin директивы parallel определяет порядок инициализации threadprivate-переменных: эти переменные
инициализируются значением на master-треде в начале параллельного участка.

Слайд 20

Управление распределением вычислений

Для распределения вычислений применяются
конструкции:
for
sections
single

Управление распределением вычислений Для распределения вычислений применяются конструкции: for sections single

Слайд 21

Директива for

#pragma omp for [clause ...]
clause:
schedule (type [,chunk])
ordered

Директива for #pragma omp for [clause ...] clause: schedule (type [,chunk]) ordered

private (list)
firstprivate (list)
lastprivate (list)
reduction (operator: list)
nowait

Слайд 22

Директива предшествует циклу for канонического типа:
for(init-expr, var logical_op b, incr_expr)
init_expr ::=

Директива предшествует циклу for канонического типа: for(init-expr, var logical_op b, incr_expr) init_expr
var = expr
logical_op >, <, >=, <=

Слайд 23

incr_expr ::= var ++
++ var
var --
-- var
var += incr
var -= incr
var

incr_expr ::= var ++ ++ var var -- -- var var +=
= incr + var
var = var + incr
var = var – incr
var переменная целого типа
incr, lb, b инварианты цикла целого типа

Слайд 24

Опция shedule директивы for

Опция shedule допускает следующие аргументы:
static - распределение осуществляется статически;
dynamic

Опция shedule директивы for Опция shedule допускает следующие аргументы: static - распределение
- распределение осуществляется динамически (тред,
закончивший выполнение, получает новую порцию итераций);
guided - аналогично dynamic, но на каждой следующей итерации
размер распределяемого блока итераций равен примерно общему
числу оставшихся итераций, деленному на число исполняемых
тредов, если это число больше заданного значения chunk, или
значению chunk в противном случае (крупнее порция – меньше синхронизаций)
runtime - распределение осуществляется во время выполнения
системой поддержки времени выполнения (параметр chunk не
задается) на основе переменных среды

Слайд 25

Особенности опции schedule директивы for

аргумент chunk можноиспользовать только вместе с типами

Особенности опции schedule директивы for аргумент chunk можноиспользовать только вместе с типами
static, dynamic, guided
по умолчанию chunk считается равным 1
распараллеливание с помощью опции runtime осуществляется используя значение переменной OMP_SCHEDULE Пример. setenv OMP_SCHEDULE “guided,4”

Слайд 26

#include #include #include main(int argc, char* argv[]) { int n, iters, t, i,

#include #include #include main(int argc, char* argv[]) { int n, iters, t,
j; double *a, *b, *c, alpha = 0.1; n = atoi(argv[1]); iters = atoi(argv[2]); a = (double*)malloc(n * sizeof(double)); b = (double*)malloc(n * sizeof(double)); t = time(NULL); for(i = 0; i < iters; i ++) { for(j = 0; j < n; j ++) { a[j] = a[j] + alpha * b[j]; } } t = time(NULL) - t; printf("sequential loop: %d seconds\n", t); }

Сложение (с умножением) векторов – последовательный вариант.

Слайд 27

#include #include #include #include
main(int argc, char* argv[]) { int n, iters, t,

#include #include #include #include main(int argc, char* argv[]) { int n, iters,
i, j; double *a, *b, alpha = 0.1; n = atoi(argv[1]); iters = atoi(argv[2]);
a = (double*)malloc(n * sizeof(double)); b = (double*)malloc(n * sizeof(double)); t = time(NULL); for(i = 0; i < iters; i ++) {
#pragma omp parallel for private(j), firstprivate(n) for(j = 0; j < n; j ++) { a[j] = a[j] + alpha * b[j]; } } t = time(NULL) - t; printf("parallel loop: %d seconds\n", t); }

Сложение (с умножением) векторов – параллельный вариант.

Слайд 28

Результаты эксперимента

Компьютер: 2 x 64-разрядный процессор Intel® Itanium-2® 1.6 ГГц.

Результаты эксперимента Компьютер: 2 x 64-разрядный процессор Intel® Itanium-2® 1.6 ГГц.

Слайд 29

Директива sections

#pragma omp sections [clause ...]
structured_block
clause: private (list)
firstprivate (list)

Директива sections #pragma omp sections [clause ...] structured_block clause: private (list) firstprivate
lastprivate (list)
reduction (operator: list)
nowait
{
#pragma omp section
structured_block
#pragma omp section
structured_block
}

Слайд 30

Опция lastprivate обладает той же семантикой, что и
опция private. При этом,

Опция lastprivate обладает той же семантикой, что и опция private. При этом,
значение переменной после завершения блока параллельного исполнения определяется как ее значение на последней итерации цикла или в последней секции для work-sharing конструкций (с точки зрения последовательного выполнения).

Опция lastprivate

М

Слайд 31

Директива single

#pragma omp single [clause ...]
structured_block
Директива single определяет что последующий
блок будет

Директива single #pragma omp single [clause ...] structured_block Директива single определяет что
выполняться только одним тредом

Слайд 32

Директивы синхронизации

master
critical
barrier
atomic
flush
ordered

Директивы синхронизации master critical barrier atomic flush ordered

Слайд 33

#pragma omp master
определяет секцию кода, выполняемого только master-тредом
#pragma omp critical [(name)]
определяет секцию

#pragma omp master определяет секцию кода, выполняемого только master-тредом #pragma omp critical
кода, выполняемого только одним тредом в данный момент времени
#pragma omp barrier
определяет секцию кода, выполняемого только одним тредом в данный момент времени

Слайд 34

#pragma omp atomic

::==
x binop = expr
x ++
++ x
x --
-- x

#pragma omp atomic ::== x binop = expr x ++ ++ x x -- -- x

Слайд 35

#paragma omp flush [var-list]
::==
x binop = expr
x ++
++ x
x --
--

#paragma omp flush [var-list] ::== x binop = expr x ++ ++
x
Следующие содержат неявный flush: barrier, вход и выход из critical, ordered, выход из parallel, for, sections, single

Слайд 36

Решение уравнения Пуассона методом верхней релаксации

d2u/dx2 + d2u/dy2 – a * u =

Решение уравнения Пуассона методом верхней релаксации d2u/dx2 + d2u/dy2 – a *
f

1

1

-1

-1

(1-x2)(1-y2)

Слайд 37

Разностная схема

uijnew = uij – w /b *((ui-1,j + ui+1,j)/dx2 + (ui,j-1

Разностная схема uijnew = uij – w /b *((ui-1,j + ui+1,j)/dx2 +
+ +ui,j+1)/dy2 + b * ui,j – fi,j)
b = - (2/dx2 + 2/dy2 + a)