SlideShare ist ein Scribd-Unternehmen logo
1 von 81
Downloaden Sie, um offline zu lesen
КурносовМихаил Георгиевич 
E-mail: mkurnosov@gmail.com 
WWW: www.mkurnosov.net 
Курс “Высокопроизводительные вычислительные системы” 
Сибирский государственный университет телекоммуникаций и информатики (Новосибирск) 
Осенний семестр, 2014 
Лекция 6Стандарт OpenMP
Программный инструментарий 
2 
Hardware (Multi-core processors, SMP/NUMA) 
Kernel thread 
Process/thread scheduler 
Системные вызовы (System calls) 
POSIX Threads 
Apple OS X Cocoa, Pthreads 
Уровень ядра 
(Kernel space) 
Операционная система (Operating System) GNU/Linux, Microsoft Windows, Apple OS X, IBM AIX, Oracle Solaris, … 
Kernel thread 
Kernel thread 
… 
Уровень пользователя (User space) 
Системные библиотеки(System libraries) 
Thread 
Thread 
Thread 
Thread 
… 
Win32 API/.NET Threads 
Thread 
Thread 
Thread 
Thread 
Kernel thread 
Kernel thread 
Kernel thread 
Kernel thread 
Kernel thread 
Intel Threading Building Blocks (TBB) 
Microsoft Concurrency Runtime 
Apple Grand Central Dispatch 
Boost Threads 
Qthread, MassiveThreads 
Прикладные библиотеки 
Языки программирования 
OpenMP(C/C++/Fortran) 
Intel CilkPlus 
С++11 Threads 
C11 Threads 
C# Threads 
Java Threads 
ErlangThreads 
Haskell Threads
Стандарт OpenMP 
3 
OpenMP(OpenMulti-Processing) –стандарт, определяющий набор директив компилятора, библиотечных процедур и переменных среды окружения для создания многопоточных программ 
Разрабатывается в рамках OpenMPArchitecture Review Board с 1997 года 
http://www.openmp.org 
OpenMP2.5 (2005), OpenMP3.0 (2008), OpenMP3.1 (2011), OpenMP4.0 (2013) 
Требуется поддержка со стороны компилятора
OpenMP 
4 
Compiler 
Information 
GNU GCC 
Option:–fopenmpgcc4.2 –OpenMP2.5, gcc4.4 –OpenMP3.0, gcc4.7 –OpenMP3.1 
gcc4.9 –OpenMP4.0 
Clang(LLVM) 
OpenMP3.1 
Clang + Intel OpenMPRTL 
http://clang-omp.github.io/ 
IntelC/C++, Fortran 
OpenMP3.1 
Option: –Qopenmp,–openmp 
Oracle Solaris Studio C/C++/Fortran 
OpenMP3.1 
Option: –xopenmp 
MicrosoftVisual Studio 2012 C++ 
Option: /openmp 
OpenMP2.0 only 
Other compilers: IBM XL, PathScale, PGI, AbsoftPro, … http://openmp.org/wp/openmp-compilers/
Структура OpenMP-программы 
5 
Программа представляется в виде последовательных участков кода (serial code) и параллельных регионов (parallel region) 
Каждый поток имеет номер: 0, 1, 2, … 
Главный поток (master) имеет номер 0 
Память процессаявляется общей для всех потоков 
OpenMPреализует динамическое управление потоками (task parallelism) 
OpenMP: data parallelism + task parallelism 
0 
0 
1 
2 
0 
1 
0 
Барьерная синхронизация
Пример OpenMP-программы 
6 
#include <omp.h> 
intmain() 
{ 
#pragma ompparallel 
{ 
printf("Thread %dn", omp_get_thread_num()); 
} 
return0; 
}
Компиляция OpenMP-программы 
7 
$ gcc–fopenmp–o prog./prog.c 
$ ./prog 
Thread 0 
Thread 1 
Thread 3 
Thread 2 
$ export OMP_NUM_THREADS=2 
$ ./prog 
Thread 0 
Thread 1 
По умолчанию количество потоков = количеству логических процессоров в системе
Пример OpenMP-программы 
8 
#include <omp.h> 
intmain() 
{ 
#pragma ompparallel 
{ 
#ifdef_OPENMP 
printf("Thread %dn", omp_get_thread_num()); 
#endif 
} 
return0; 
}
Компиляция OpenMP-программы 
9 
$ g++ -Wall -fopenmp-o hello ./hello.cpp 
$ ./hello 
Hello, OpenMPWorld! 
Hello, OpenMPWorld! 
Hello, OpenMPWorld! 
Hello, OpenMPWorld! 
$ g++ -Wall -o hello ./hello.cpp 
./hello.cpp:5:0: warning: ignoring #pragma ompparallel 
[-Wunknown-pragmas] 
$ ./hello 
Hello, OpenMPWorld!
Синтаксис директив OpenMP 
10 
Языки С/C++ #pragma ompdirective-name[clause[ [,] clause]...] new-line#pragmaompparallel 
Fortransentinel directive-name[clause[[,] clause]...] !$ompparallel 
Создание потоков 
Распределение вычислений между потоками 
Управление пространством видимости переменных 
Синхронизация потоков 
…
Создание потоков(parallel) 
11 
#pragma ompparallel 
{ 
/* Этот код выполняется всеми потоками */ 
} 
#pragma ompparallel if (expr) 
{ 
/* Код выполняется потоками если expr= true */ 
} 
#pragma ompparallel num_threads(n / 2) 
{ 
/* Создается n / 2 потоков*/ 
} 
На выходе из параллельного региона осуществляется барьерная синхронизация –все потоки ждут последнего
Создание потоков(sections) 
12 
#pragma ompparallel sections 
{ 
#pragma ompsection 
{ 
/* Код потока 0 */ 
} 
#pragma ompsection 
{ 
/* Код потока 1 */ 
} 
} 
При любых условиях выполняется фиксированное количество потоков (по количеству секций)
Функции runtime-библиотеки 
13 
intomp_get_thread_num() –возвращает номер текущего потока 
intomp_get_num_threads() –возвращает количество потоков в параллельном регионе 
void omp_set_num_threads(intn) 
double omp_get_wtime()
Директиваmaster 
14 
#pragma ompparallel 
{ 
/* Этот код выполняется всеми потоками */ 
#pragma ompmaster 
{ 
/* Код выполняется только потоком 0 */ 
} 
/* Этот код выполняется всеми потоками */ 
}
Директиваsingle 
15 
#pragma ompparallel 
{ 
/* Этот код выполняется всеми потоками */ 
#pragma ompsingle 
{ 
/* Код выполняется только одним потоком */ 
} 
/* Этот код выполняется всеми потоками */ 
}
Директиваfor(data parallelism) 
16 
#define N 13 
#pragma ompparallel 
{ 
#pragma ompfor 
for(i = 0; i < N; i++) { 
printf("Thread %d i = %dn", 
omp_get_thread_num(), i); 
} 
} 
Итерации цикла распределяются между потоками 
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
i: 
Thread 0 
Thread 1 
Thread 2 
Thread 3
Директива for 
17 
$ OMP_NUM_THREADS=4 ./prog 
Thread 2 i = 7 
Thread 2 i = 8 
Thread 2 i = 9 
Thread 0 i = 0 
Thread 0 i = 1 
Thread 0 i = 2 
Thread 3 i = 10 
Thread 3 i = 11 
Thread 3 i = 12 
Thread 0 i = 3 
Thread 1 i = 4 
Thread 1 i = 5 
Thread 1 i = 6
Алгоритмы распределения итераций 
18 
#define N 13 
#pragma ompparallel 
{ 
#pragma ompfor schedule(static, 2) 
for(i = 0; i < N; i++) { 
printf("Thread %d i = %dn", 
omp_get_thread_num(), i); 
} 
} 
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
i: 
Итерации цикла распределяются циклически (round-robin) блоками по 2 итерации 
T0 
T1 
T2 
T3 
T0 
T1 
T2
Алгоритмы распределения итераций 
19 
$ OMP_NUM_THREADS=4 ./prog 
Thread 0 i = 0 
Thread 0 i = 1 
Thread 0 i = 8 
Thread 0 i = 9 
Thread 1 i = 2 
Thread 1 i = 3 
Thread 1 i = 10 
Thread 1 i = 11 
Thread 3 i = 6 
Thread 3 i = 7 
Thread 2 i = 4 
Thread 2 i = 5 
Thread 2 i = 12
Алгоритм 
Описание 
static, m 
Цикл делится на блоки поmитераций (до выполнения),которые распределяются по потокам 
dynamic, m 
Цикл делится на блоки поm итераций. 
При выполнении блока из mитераций поток выбирает следующий блок из общего пула 
guided, m 
Блоки выделяются динамически. При каждом запросе размер блока уменьшается экспоненциальнодо m 
runtime 
Алгоритм задается пользователем через переменную среды OMP_SCHEDULE 
Алгоритмы распределения итераций 
20
Директиваfor(ordered) 
21 
#define N 7 
#pragma ompparallel 
{ 
#pragma ompfor ordered 
for(i = 0; i < N; i++) { 
#pragma ompordered 
printf("Thread %d i = %dn", 
omp_get_thread_num(), i); 
} 
} 
Директива ordered организует последовательное выполнение итераций (i= 0, 1, …)–синхронизация 
Поток с i= kожидает пока потоки сi = k–1, k–2, … не выполнятсвои итерации
Директива for(ordered) 
22 
$ OMP_NUM_THREADS=4 ./prog 
Thread 0 i = 0 
Thread 0 i = 1 
Thread 1 i = 2 
Thread 1 i = 3 
Thread 2 i = 4 
Thread 2 i = 5 
Thread 3 i = 6
Директиваfor(nowait) 
23 
#define N 7 
#pragma ompparallel 
{ 
#pragma ompfor nowait 
for(i = 0; i < N; i++) { 
printf("Thread %d i = %dn", 
omp_get_thread_num(), i); 
} 
} 
По окончанию цикла потоки не выполняют барьерную синхронизацию 
Конструкция nowaitприменима и к директиве sections
Директиваfor (collapse) 
24 
#define N 3 
#define M 4 
#pragma ompparallel 
{ 
#pragma ompfor collapse(2) 
for (i = 0; i < N; i++) { 
for (j = 0; j < M; j++) 
printf("Thread %d i = %dn", 
omp_get_thread_num(), i); 
} 
} 
сollapse(n)объединяет пространство итераций nциклов в одно 
0 
1 
2 
0 
1 
2 
3 
i: 
j: 
0,0 
0,1 
0,2 
0,3 
1,0 
1,1 
1,2 
1,3 
2,0 
2,1 
2,2 
2,3 
T0 
+ 
T1 
T2 
T3
Директива for (collapse) 
25 
$ OMP_NUM_THREADS=4 ./prog 
Thread 2 i = 1 
Thread 2 i = 1 
Thread 2 i = 2 
Thread 0 i = 0 
Thread 0 i = 0 
Thread 0 i = 0 
Thread 3 i = 2 
Thread 3 i = 2 
Thread 3 i = 2 
Thread 1 i = 0 
Thread 1 i = 1 
Thread 1 i = 1
#include <iostream> 
#include <vector> 
intmain() 
{ 
std::vector<int> vec(1000); 
std::fill(vec.begin(), vec.end(), 1); 
intcounter = 0; 
#pragma ompparallel for 
for(std::vector<int>::size_typei= 0; 
i< vec.size(); i++) 
{ 
if(vec[i] > 0) { 
counter++; 
} 
} 
std::cout<< "Counter = "<< counter << std::endl; 
return0; 
} 
Ошибки в многопоточных программах 
26
Ошибки в многопоточных программах 
27 
$ g++ –fopenmp–o ompprog./ompprog.cpp 
$ ./omprog 
Counter = 381 
$ ./omprog 
Counter = 909 
$ ./omprog 
Counter = 398 
На каждом запуске итоговое значение Counter разное! 
Правильный результат Counter = 1000
#include <iostream> 
#include <vector> 
intmain() 
{ 
std::vector<int> vec(1000); 
std::fill(vec.begin(), vec.end(), 1); 
intcounter = 0; 
#pragma ompparallel for 
for(std::vector<int>::size_typei= 0; 
i< vec.size(); i++) 
{ 
if(vec[i] > 0) { 
counter++; 
} 
} 
std::cout<< "Counter = "<< counter << std::endl; 
return0; 
} 
Ошибки в многопоточных программах 
28 
Потоки осуществляют конкурентный доступ к переменной counter – одновременно читают её и записывают
Thread 0 
Thread 1 
Memory(counter) 
0 
movl[counter], %eax 
← 
0 
incl%eax 
0 
movl%eax, [counter] 
→ 
1 
movl[counter], %eax 
← 
1 
incl%eax 
1 
movl%eax, [counter] 
→ 
2 
Состояние гонки (Race condition, data race) 
29 
#pragma ompparallel 
{ 
counter++; 
} 
movl[counter], %eax 
incl%eax 
movl%eax, [counter] 
C++ 
Идеальнаяпоследовательность выполнения инструкций 2-х потоков 
counter= 2
Thread 0 
Thread 1 
Memory(counter) 
0 
movl[counter], %eax 
← 
0 
incl%eax 
movl[counter], %eax 
← 
0 
movl%eax, [counter] 
incl%eax 
→ 
1 
movl%eax, [counter] 
→ 
1 
1 
Состояние гонки (Race condition, data race) 
30 
movl[counter], %eax 
incl%eax 
movl%eax, [counter] 
C++ 
Возможнаяпоследовательность выполнения инструкций 2-х потоков 
counter=1 
Error: Data race 
#pragma ompparallel 
{ 
counter++; 
}
Состояние гонки (Race condition, data race) 
31 
Состояние гонки (Race condition, data race) – это состояние программы, в которой несколько потоков одновременно конкурируют за доступ к общей структуре данных (для чтения/записи) 
Порядок выполнения потоков заранеене известен – носит случайный характер 
Планировщик динамически распределяет процессорное время учитывая текущую загруженность процессорных ядер, а нагрузку (потоки, процессы) создают пользователи, поведение которых носит случайных характер 
Состояние гонки данных (Race condition, data race) трудно обнаруживается в программах и воспроизводится в тестах 
Состояние гонки данных (Race condition, data race)– это типичный пример Гейзенбага(Heisenbug)
Обнаружение состояния гонки (Data race) 
32 
Динамические анализаторы 
ValgrindHelgrind, DRD 
Intel Thread Checker 
Oracle Studio Thread Analyzer 
Java ThreadSanitizer 
Java Chord 
Статические анализаторы кода 
PVS-Studio (viva64) 
…
==8238== Helgrind, a thread error detector 
==8238== Copyright (C) 2007-2012, and GNU GPL'd, by OpenWorksLLP et al. 
==8238== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info 
==8238== Command: ./ompprogreport 
... 
==8266== ---------------------------------------------------------------- 
==8266== Possible data race during write of size 4 at 0x7FEFFD358 by thread #3 
==8266== Locks held: none 
==8266== at 0x400E6E: main._omp_fn.0 (ompprog.cpp:14) 
==8266== by 0x3F84A08389: ??? (in /usr/lib64/libgomp.so.1.0.0) 
==8266== by 0x4A0A245: ??? (in /usr/lib64/valgrind/vgpreload_helgrind-amd64-linux.so) 
==8266== by 0x34CFA07C52: start_thread(in /usr/lib64/libpthread-2.17.so) 
==8266== by 0x34CF2F5E1C: clone (in /usr/lib64/libc-2.17.so) 
==8266== 
==8266== This conflicts with a previous write of size 4 by thread #1 
==8266== Locks held: none 
==8266== at 0x400E6E: main._omp_fn.0 (ompprog.cpp:14) 
==8266== by 0x400CE8: main (ompprog.cpp:11)... 
ValgrindHelgrind 
33 
$ g++ -fopenmp-o ompprog./ompprog.cpp 
$ valgrind--tool=helgrind./ompprog
Директивы синхронизации 
34 
Директивы синхронизации позволяют управлять порядком выполнения заданных участков кода потоками 
#pragma ompcritical 
#pragma ompatomic 
#pragma ompordered 
#pragma ompbarrier
#pragma ompparallel for private(v) 
for(i = 0; i < n; i++) { 
v = fun(a[i]); 
#pragma ompcritical 
{ 
sum += v; 
} 
} 
Критические секции 
35
#pragma ompparallel for private(v) 
for(i = 0; i < n; i++) { 
v = fun(a[i]); 
#pragma ompcritical 
{ 
sum += v; 
} 
} 
Критическая секция (Critical section)–участок кода в многопоточной программе, выполняемый всеми потоками последовательно 
Критические секции снижают степень параллелизма 
Критические секции 
36
Управление видимостью переменных 
37 
private(list) –во всех потоках создаются локальные копиипеременных (начальное значение) 
firstprivate(list) –во всех потоках создаются локальные копии переменных, которые инициализируются их значениями до входа в параллельный регион 
lastprivate(list) –во всех потоках создаются локальные копии переменных. По окончанию работы всех потоков локальная переменная вне параллельного региона обновляется значением этой переменной одного из потоков 
shared(list) –переменные являются общими для всех потоков 
threadprivate(list)
Атомарные операции 
38 
#pragma ompparallel for private(v) 
for(i = 0; i < n; i++) { 
v = fun(a[i]); 
#pragma ompatomic 
sum += v; 
}
Атомарные операции 
39 
#pragma ompparallel for private(v) 
for(i = 0; i < n; i++) { 
v = fun(a[i]); 
#pragma ompatomic 
sum += v; 
} 
Атомарные операции “легче”критических секций (не используют блокировки) 
Lock-free algorithms & data structures
Параллельная редукция 
40 
#pragma ompparallel for reduction(+:sum) 
for(i = 0; i < n; i++) { 
sum = sum + fun(a[i]); 
} 
Операции директивы reduction: +, *, -, &, |, ^, &&, ||, max, min 
OpenMP4.0поддерживает пользовательские функции редукции
Директивы синхронизации 
41 
#pragma ompparallel 
{ 
/* Code */ 
#pragma ompbarrier 
/* Code */ 
} 
Директива barrierосуществляет ожидание достижения данной точки программы всеми потоками
#pragma ompflush 
42 
#pragma ompparallel 
{ 
/* Code */ 
#pragma ompflush(a, b) 
/* Code */ 
} 
Принудительно обновляет в памяти значения переменных(Memory barrier) 
Например, в одном потоке выставляем флаг (сигнал к действию) для другого
Умножение матриц v1.0 
43 
#pragma ompparallel 
{ 
#pragma ompfor 
for(i = 0; i < N; i++) { 
for(j = 0; j < N; j++) { 
for(k = 0; k < N; k++) { 
c[i][j] = c[i][j] + 
a[i][k] * b[k][j]; 
} 
} 
} 
}
Умножение матриц v1.0 
44 
#pragma ompparallel 
{ 
#pragma ompfor 
for(i = 0; i < N; i++) { 
for(j = 0; j < N; j++) { 
for(k = 0; k < N; k++) { 
c[i][j] = c[i][j] + 
a[i][k] * b[k][j]; 
} 
} 
} 
} 
Ошибка! 
Переменные j, k–общие для всех потоков!
Умножение матриц v2.0 
45 
#pragma ompparallel 
{ 
#pragma ompforshared(a, b, c) private(j, k) 
for(i = 0; i < N; i++) { 
for(j = 0; j < N; j++) { 
for(k = 0; k < N; k++) { 
c[i][j] = c[i][j] + 
a[i][k] * b[k][j]; 
} 
} 
} 
}
Пример Primes (sequential code) 
46 
start = atoi(argv[1]); 
end = atoi(argv[2]); 
if((start % 2) == 0 ) 
start = start + 1; 
nprimes= 0; 
if(start <= 2) 
nprimes++; 
for(i= start; i<= end; i+= 2) { 
if(is_prime_number(i)) 
nprimes++; 
} 
Программа подсчитывает количество простых чисел в интервале [start, end]
Пример Primes (serial code) 
47 
intis_prime_number(intnum) 
{ 
intlimit, factor = 3; 
limit = (int)(sqrtf((double)num) + 0.5f); 
while ((factor <= limit) && (num% factor)) 
factor++; 
return(factor > limit); 
}
start = atoi(argv[1]); 
end = atoi(argv[2]); 
if((start % 2) == 0 ) 
start = start + 1; 
nprimes= 0; 
if(start <= 2) 
nprimes++; 
#pragma ompparallel for 
for(i= start; i<= end; i+= 2) { 
if(is_prime_number(i)) 
nprimes++; 
} 
Пример Primes (parallel code) 
48
start = atoi(argv[1]); 
end = atoi(argv[2]); 
if((start % 2) == 0 ) 
start = start + 1; 
nprimes= 0; 
if(start <= 2) 
nprimes++; 
#pragma ompparallel for 
for(i= start; i<= end; i+= 2) { 
if(is_prime_number(i)) 
nprimes++; 
} 
Пример Primes (parallel code) 
49 
Data race
start = atoi(argv[1]); 
end = atoi(argv[2]); 
if((start % 2) == 0 ) 
start = start + 1; 
nprimes= 0; 
if(start <= 2) 
nprimes++; 
#pragma ompparallel for 
for(i= start; i<= end; i+= 2) { 
if(is_prime_number(i)) 
#pragma ompcritical 
nprimes++; 
} 
Пример Primes (parallel code) 
50
start = atoi(argv[1]); 
end = atoi(argv[2]); 
if((start % 2) == 0 ) 
start = start + 1; 
nprimes= 0; 
if(start <= 2) 
nprimes++; 
#pragma ompparallel for 
for(i= start; i<= end; i+= 2) { 
if(is_prime_number(i)) 
#pragma ompcritical 
nprimes++; 
} 
Пример Primes (parallel code) 
51 
Увеличение счетчика можно реализовать без блокировки 
(Lock-free algorithm)
start = atoi(argv[1]); 
end = atoi(argv[2]); 
if((start % 2) == 0 ) 
start = start + 1; 
nprimes= 0; 
if(start <= 2) 
nprimes++; 
#pragma ompparallel forreduction(+:nprimes) 
for(i= start; i<= end; i+= 2) { 
if(is_prime_number(i)) 
nprimes++; 
} 
Пример Primes (parallel code) 
52
start = atoi(argv[1]); 
end = atoi(argv[2]); 
if((start % 2) == 0 ) 
start = start + 1; 
nprimes= 0; 
if(start <= 2) 
nprimes++; 
#pragma ompparallel forreduction(+:nprimes) 
for(i= start; i<= end; i+= 2) { 
if(is_prime_number(i)) 
nprimes++; 
} 
Пример Primes (parallel code) 
53 
Время выполнения is_prime_number(i) зависит отзначения i
#pragma ompparallel forreduction(+:nprimes) 
for(i= start; i<= end; i+= 2) { 
if(is_prime_number(i)) 
nprimes++; 
} 
Пример Primes (parallel code) 
54 
Поток 0 
Поток 1 
Поток 2 
Поток 3 
Поток 4 
Время выполнения потоков различно! 
Load Imbalance
Пример Primes (parallel code) 
55 
start = atoi(argv[1]); 
end = atoi(argv[2]); 
if((start % 2) == 0 ) 
start = start + 1; 
nprimes= 0; 
if(start <= 2) 
nprimes++; 
#pragma ompparallel for schedule(static, 1) 
reduction(+:nprimes) 
for(i = start; i <= end; i += 2) { 
if(is_prime_number(i)) 
nprimes++; 
}
Вычисление числа 흅 
56 
0,00 
0,50 
1,00 
1,50 
2,00 
2,50 
3,00 
3,50 
4,00 
4,50 
0,00 0,10 0,20 0,30 0,40 0,50 0,60 0,70 0,80 0,90 
휋 = 
0 
1 
4 
1 + 푥2 푑푥 휋 ≈ ℎ 
푖=1 
푛 
4 
1 + (ℎ(푖 − 0.5))2 ℎ = 
1 
푛
Вычисление числа 흅 
57 
0,00 
0,50 
1,00 
1,50 
2,00 
2,50 
3,00 
3,50 
4,00 
4,50 
0,00 0,10 0,20 0,30 0,40 0,50 0,60 0,70 0,80 0,90 
휋 = 
0 
1 
4 
1 + 푥2 푑푥 휋 ≈ ℎ 
푖=1 
푛 
4 
1 + (ℎ(푖 − 0.5))2 
ℎ = 
1 
푛 
// Последовательная версия 
int main() { 
// ... 
nsteps = 1000000; 
step = 1.0 / nsteps; 
sum = 0.0; 
for (i = 1; i <= nsteps; i++) { 
x = (i - 0.5) * step; 
sum = sum + 4.0 / (1.0 + x * x); 
} 
pi = step * sum; 
printf("Pi = %.16fn", pi); 
return 0; 
} 
ℎ = 
1 
푛
Вычисление числа 흅(OpenMP) 
58 
intmain(intargc, char**argv) { // ... intnthreads= omp_get_max_threads(); doublesumloc[nthreads]; doublesum = 0.0; #pragmaompparallel{ inttid= omp_get_thread_num(); sumloc[tid] = 0.0; #pragmaompfor nowaitfor(inti = 1; i <= nsteps; i++) { doublex = (i-0.5) * step; sumloc[tid] += 4.0 / (1.0 + x * x); } #pragmaompcriticalsum += sumloc[tid]; } doublepi = step * sum; printf("PI is approximately %.16f, Error is %.16fn", pi, fabs(pi -PI25DT)); // ... }
Вычисление числа 흅(OpenMP) intmain(intargc, char**argv) { // ... intnthreads= omp_get_max_threads(); doublesumloc[nthreads]; doublesum = 0.0; #pragmaompparallel{ inttid= omp_get_thread_num(); sumloc[tid] = 0.0; #pragmaompfor nowaitfor(inti = 1; i <= nsteps; i++) { doublex = (i-0.5) * step; sumloc[tid] += 4.0 / (1.0 + x * x); } #pragmaompcriticalsum += sumloc[tid]; } doublepi = step * sum; printf("PI is approximately %.16f, Error is %.16fn", pi, fabs(pi -PI25DT)); // ... } 
Shared memory (RAM) 
Core 0 (Thread 0) 
Cache 
Core 1 (Thread 1) 
Cache 
MESI (Intel MESIF) cache coherency protocol 
sumloc[0], sumloc[1], … 
могут попасть в одну строку кеш-памяти 
сachelineобновляется несколькими потоками – кеширование “отключается” 
Cacheline 
sumloc[0] 
Cacheline 
sumloc[1] 
False sharing (ложное разделение)
Вычисление числа 흅(OpenMP)v2 
60 
structthreadparams{ doublesum; doublepadding[7]; // Padding for cachelinesize (64 bytes) }; intmain(intargc, char**argv) { // ... threadparamssumloc[nthreads] __attribute__ ((aligned(64))); //double sumloc[nthreads* 8]; doublesum = 0.0; #pragmaompparallel num_threads(nthreads) { inttid= omp_get_thread_num(); sumloc[tid].sum = 0.0; #pragmaompfornowaitfor(inti = 1; i <= nsteps; i++) { doublex = (i-0.5) * step; sumloc[tid].sum += 4.0 / (1.0 + x * x); } #pragmaompcriticalsum += sumloc[tid].sum; } // ... } 
Avoiding and Identifying False Sharing Among Threads // http://software.intel.com/en-us/articles/avoiding-and-identifying-false-sharing-among-threads
Вычисление числа 흅(OpenMP)v2.1 
61 
// ... doublesum = 0.0; #pragmaompparallel num_threads(nthreads) { doublesumloc= 0.0; // Избавились от массива#pragmaompfornowaitfor(inti = 1; i <= nsteps; i++) { doublex = (i-0.5) * step; sumloc+= 4.0 / (1.0 + x * x); } #pragmaompcriticalsum += sumloc; } doublepi = step * sum; // ...
Директива task(OpenMP3.0) 
62 
intfib(intn) 
{ 
if(n < 2) 
returnn; 
returnfib(n -1) + fib(n -2); 
} 
Директива task создает задачу (легковесный поток) 
Задачи из пула динамически выполняются группой потоков 
Динамическое распределение задача по потокам осуществляется алгоритмами планирования типа work stealing 
Задач может быть намного больше количества потоков
Директива task(OpenMP3.0) 
63 
intfib(intn) 
{ 
intx, y; 
if(n < 2) 
returnn; 
#pragma omptask shared(x, n) 
x = fib(n -1); 
#pragma omptask shared(y, n) 
y = fib(n -2); 
#pragma omptaskwait 
returnx + y; 
} 
#pragma ompparallel 
#pragma ompsingle 
val= fib(n); 
Каждый рекурсивный вызов –это задача 
Ожидаем завершение дочерних задач
Директива task(OpenMP3.0) 
64 
fib(1) 
fib(0) 
fib(2) 
fib(3) 
fib(1) 
fib(1) 
fib(0) 
fib(2) 
fib(4) 
Легковесные задачи (tasks) 
0 
1 
2 
3 
Очереди (деки) задач + 
пул потоков операционной системы 
Need tasks 
Spawn 
Sync
Вложенные параллельные регионы 
65 
voidlevel2() { #pragmaompparallel sections { #pragmaompsection{printf("L2 1 Thread PID %un", (unsignedint)pthread_self()); } #pragmaompsection{printf("L2 2 Thread PID %un", (unsignedint)pthread_self());} } } voidlevel1() { #pragmaompparallel sections num_threads(2) { #pragmaompsection{printf("L1 1 Thread PID %un", (unsignedint)pthread_self()); level2(); } #pragmaompsection{printf("L1 2 Thread PID %un", (unsignedint)pthread_self()); level2(); } } } intmain() {omp_set_dynamic(0); omp_set_nested(1); level1(); }
Вложенные параллельные регионы 
66 
voidlevel2() { #pragmaompparallel sections { #pragmaompsection{printf("L2 1 Thread PID %un", (unsignedint)pthread_self()); } #pragmaompsection{printf("L2 2 Thread PID %un", (unsignedint)pthread_self());} } } voidlevel1() { #pragmaompparallel sections num_threads(2) { #pragmaompsection{printf("L1 1 Thread PID %un", (unsignedint)pthread_self()); level2(); } #pragmaompsection{printf("L1 2 Thread PID %un", (unsignedint)pthread_self()); level2(); } } } intmain() {omp_set_dynamic(0); omp_set_nested(1); level1(); } 
Section 2 
Section 1 
Section 1 
Section 2 
PID = 210 
PID = 100 
PID = 100 
main() 
sections 
num_threads(2) 
Количество потоков8 (1 + 1 + 3 + 3) 
Поток, создавший параллельный регион, входит в состав новой группы (создается n–1 потоков)
Рекурсивный параллелизм(QuickSort) 
67 
voidpartition(int*v, int& i, int& j, intlow, inthigh) { i= low; j = high; intpivot = v[(low + high) / 2]; do{ while(v[i] < pivot) i++; while(v[j] > pivot) j--; if(i<= j) { std::swap(v[i], v[j]); i++; j--; } } while(i<= j); } voidquicksort(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); if(low < j) quicksort(v, low, j); if(i< high) quicksort(v, i, high); }
QuickSortv1 (nested sections) 
68 
omp_set_nested(1); // Enable nested parallel regionsvoidquicksort_nested(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); #pragmaompparallel sections num_threads(2) { #pragmaompsection{ if(low < j) quicksort_nested(v, low, j); } #pragmaompsection{ if(i< high) quicksort_nested(v, i, high); } } } 
Минусы 
Неограниченная глубина вложенных параллельных регионов 
Отдельные потоки создаются даже для сортировки коротких отрезков [low, high]
QuickSortv2 (max_active_levels) 
69 
omp_set_nested(1); // Maximum allowed number of nested, active parallel regionsomp_set_max_active_levels(4); voidquicksort_nested(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); #pragmaompparallel sections num_threads(2) { #pragmaompsection{ if(low < j) quicksort_nested(v, low, j); } #pragmaompsection{ if(i< high) quicksort_nested(v, i, high); } } }
QuickSortv3 (пороговое значение) 
70 
omp_set_nested(1); // Enable nested parallel regionsmp_set_max_active_levels(4); // Max. number of nested parallel regionsvoidquicksort_nested(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); if(high -low < threshold|| (j -low < threshold|| high -i< threshold)) { if(low < j) // Sequential executionquicksort_nested(v, low, j); if(i< high) quicksort_nested(v, i, high); } else{ #pragmaompparallel sections num_threads(2) { #pragmaompsection{quicksort_nested(v, low, j); } #pragmaompsection{quicksort_nested(v, i, high); } } } } 
Короткие интервалы сортируем последовательным алгоритмом 
Сокращение накладных расходов на создание потоков
QuickSortv4 (task) 
71 
#pragmaompparallel{ #pragmaompsinglequicksort_tasks(array, 0, size -1); } voidquicksort_tasks(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); if(high -low < threshold || (j -low < threshold || high -i< threshold)) { if(low < j) quicksort_tasks(v, low, j); if(i< high) quicksort_tasks(v, i, high); } else{ #pragmaomptask{quicksort_tasks(v, low, j); } quicksort_tasks(v, i, high); } }
QuickSortv4 (task + untied) 
72 
#pragmaompparallel{ #pragmaompsinglequicksort_tasks(array, 0, size -1); } voidquicksort_tasks(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); if(high -low < threshold || (j -low < threshold || high -i< threshold)) { if(low < j) quicksort_tasks(v, low, j); if(i< high) quicksort_tasks(v, i, high); } else{ // Открепить задачу от потока (задачу может выполнять // любой поток) #pragmaomptask untied{quicksort_tasks(v, low, j); } quicksort_tasks(v, i, high); } }
Блокировки (locks) 
73 
Блокировка, мьютекс(lock, mutex)–это объект синхронизации, которыйпозволяет ограничить одновременный доступ потоков к разделяемым ресурсам (реализует взаимное исключение) 
OpenMP: omp_lock_set/omp_lock_unset 
POSIX Pthreads: pthread_mutex_lock/pthread_mutex_unlock 
C++11: std::mutex::lock/std::mutex::unlock 
C11: mtx_lock/mtx_unlock 
Блокировка (lock) может быть рекурсивной (вложенной) – один поток может захватывать блокировку несколько раз
#include <omp.h> 
intmain() 
{ 
std::vector<int> vec(1000); 
std::fill(vec.begin(), vec.end(), 1); 
intcounter = 0; 
omp_lock_tlock; 
omp_init_lock(&lock); 
#pragma ompparallel for 
for (std::vector<int>::size_typei= 0; i< vec.size(); i++) { 
if (vec[i] > 0) { 
omp_set_lock(&lock); 
counter++; 
omp_unset_lock(&lock); 
} 
} 
omp_destroy_lock(&lock); 
std::cout<< "Counter = " << counter << std::endl; 
return0; 
} 
Блокировки (locks) 
74
Взаимная блокировка (Deadlock) 
75 
Взаимная блокировка (deadlock, тупик)– ситуация когда два и более потока находятся в состоянии бесконечного ожидания ресурсов, захваченных этими потоками 
Самоблокировка (self deadlock) –ситуация когда поток пытается повторно захватить блокировку, которую уже захватил (deadlock возникает если блокировка не является рекурсивной)
voiddeadlock_example() 
{ 
#pragma ompsections 
{ 
#pragma ompsection 
{ 
omp_lock_tlock1, lock2; 
omp_set_lock(&lock1); 
omp_set_lock(&lock2); 
// Code 
omp_unset_lock(&lock2); 
omp_unset_lock(&lock1); 
} 
#pragma ompsection 
{ 
omp_lock_tlock1, lock2; 
omp_set_lock(&lock2); 
omp_set_lock(&lock1); 
// Code 
omp_unset_lock(&lock1); 
omp_unset_lock(&lock2); 
} 
} 
} 
Взаимная блокировка (Deadlock) 
76 
1.T0захватывает Lock1 
2.T0 ожидает Lock2 
1.T1захватывает Lock2 
2.T1 ожидает Lock1
OpenMP4.0: Поддержка ускорителей (GPU) 
77 
sum = 0; 
#pragma omptarget device(acc0) in(B,C) 
#pragma ompparallel for reduction(+:sum) 
for(i=0; i<N; i++) 
sum += B[i] * C[i] 
omp_set_default_device() 
omp_get_default_device() 
omp_get_num_devices()
OpenMP4.0: SIMD-конструкции 
78 
voidminex(float*a, float*b, float*c, float*d) 
{ 
#pragma ompparallel for simd 
for(i= 0; i< N; i++) 
d[i] = min(distsq(a[i], b[i]), c[i]); 
} 
SIMD-конструкции для векторизации циклов (SSE, AVX2, AVX-512, AltiVec, …)
OpenMP4.0: Thread Affinity 
79 
#pragma ompparallel proc_bind(master | close | spread) 
omp_proc_bind_tomp_get_proc_bind(void) 
Env. variable OMP_PLACES 
Thread affinity –привязка потоков к процессорным ядрам 
exportOMP_NUM_THREADS=16 
exportOMP_PLACES=0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15 
exportOMP_PROC_BIND=spread,close
#pragmaompdeclarereduction(merge: std::vector<int> : 
omp_out.insert(omp_out.end(), 
omp_in.begin(), omp_in.end() 
)) 
voidschedule(std::vector<int> &v, std::vector<int> &filtered) { 
#pragma ompparallel for reduction (merge: filtered) 
for(std:vector<int>::iterator it = v.begin(); 
it < v.end(); it++) 
{ 
if(filter(*it)) 
filtered.push_back(*it); 
} 
} 
OpenMP4.0: user defined reductions 
80 
#pragma ompdeclare reduction(reduction-identifier : 
typename-list : combiner) [identity(identity-expr)]
Литература 
81 
ЭхтерШ., Робертс Дж. Многоядерное программирование. –СПб.: Питер, 2010. –316 с. 
ЭндрюсГ.Р. Основы многопоточного, параллельного и распределенного программирования. –М.: Вильямс, 2003. –512 с. 
Darryl Gove. Multicore Application Programming: for Windows, Linux, and Oracle Solaris. –Addison-Wesley, 2010. –480 p. 
Maurice Herlihy, NirShavit. The Art of Multiprocessor Programming. –Morgan Kaufmann, 2008. –528 p. 
Richard H. Carver,Kuo-Chung Tai. Modern Multithreading : Implementing, Testing, and Debugging Multithreaded Java and C++/Pthreads/Win32 Programs. –Wiley-Interscience, 2005. –480 p. 
Anthony Williams. C++ Concurrency in Action: Practical Multithreading. – Manning Publications, 2012. –528 p. 
TräffJ.L. Introduction to Parallel Computing // http://www.par.tuwien.ac.at/teach/WS12/ParComp.html

Weitere ähnliche Inhalte

Was ist angesagt?

Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Mikhail Kurnosov
 
Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Mikhail Kurnosov
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...Alexey Paznikov
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksMikhail Kurnosov
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Mikhail Kurnosov
 
Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Mikhail Kurnosov
 
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...Mikhail Kurnosov
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Alexey Paznikov
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Yandex
 
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияAlexey Paznikov
 
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Alexey Paznikov
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksMikhail Kurnosov
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...Alexey Paznikov
 
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыAlexey Paznikov
 
Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)Mikhail Kurnosov
 
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...Alexey Paznikov
 
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...Alexey Paznikov
 
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!Yandex
 

Was ist angesagt? (20)

Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
 
Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)
 
Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)
 
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
 
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
 
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
 
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
 
Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)
 
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
 
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...
 
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
 

Ähnlich wie Лекция 6. Стандарт OpenMP

Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Mikhail Kurnosov
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1Michael Karpov
 
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...Ontico
 
Вечный вопрос измерения времени
Вечный вопрос измерения времениВечный вопрос измерения времени
Вечный вопрос измерения времениTatyanazaxarova
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioAndrey Karpov
 
11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)Smolensk Computer Science Club
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMTech Talks @NSU
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кодаTatyanazaxarova
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаAndrey Karpov
 
Вебинар: Основы распараллеливания С++ программ при помощи OpenMP
Вебинар: Основы распараллеливания С++ программ при помощи OpenMPВебинар: Основы распараллеливания С++ программ при помощи OpenMP
Вебинар: Основы распараллеливания С++ программ при помощи OpenMPFlyElephant
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Yandex
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаSergey Platonov
 
Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12Alex Tutubalin
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3etyumentcev
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3Eugeniy Tyumentcev
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кодаAndrey Karpov
 

Ähnlich wie Лекция 6. Стандарт OpenMP (20)

Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1
 
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
 
Вечный вопрос измерения времени
Вечный вопрос измерения времениВечный вопрос измерения времени
Вечный вопрос измерения времени
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
 
11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVM
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кода
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кода
 
Вебинар: Основы распараллеливания С++ программ при помощи OpenMP
Вебинар: Основы распараллеливания С++ программ при помощи OpenMPВебинар: Основы распараллеливания С++ программ при помощи OpenMP
Вебинар: Основы распараллеливания С++ программ при помощи OpenMP
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кода
 

Mehr von Mikhail Kurnosov

Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Mikhail Kurnosov
 
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Mikhail Kurnosov
 
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Mikhail Kurnosov
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Mikhail Kurnosov
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Mikhail Kurnosov
 
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Mikhail Kurnosov
 
Лекция 5. B-деревья (B-trees, k-way merge sort)
Лекция 5. B-деревья (B-trees, k-way merge sort)Лекция 5. B-деревья (B-trees, k-way merge sort)
Лекция 5. B-деревья (B-trees, k-way merge sort)Mikhail Kurnosov
 
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Mikhail Kurnosov
 
Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Mikhail Kurnosov
 
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Mikhail Kurnosov
 
Лекция 3. АВЛ-деревья (AVL trees)
Лекция 3. АВЛ-деревья (AVL trees)Лекция 3. АВЛ-деревья (AVL trees)
Лекция 3. АВЛ-деревья (AVL trees)Mikhail Kurnosov
 
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...Mikhail Kurnosov
 
Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)Mikhail Kurnosov
 
Лекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовЛекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовMikhail Kurnosov
 
Лекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиЛекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиMikhail Kurnosov
 
Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)Mikhail Kurnosov
 
Лекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графеЛекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графеMikhail Kurnosov
 
Семинар 8. Параллельное программирование на MPI (часть 1)
Семинар 8. Параллельное программирование на MPI (часть 1)Семинар 8. Параллельное программирование на MPI (часть 1)
Семинар 8. Параллельное программирование на MPI (часть 1)Mikhail Kurnosov
 
Лекция 8. Графы. Обходы графов
Лекция 8. Графы. Обходы графовЛекция 8. Графы. Обходы графов
Лекция 8. Графы. Обходы графовMikhail Kurnosov
 
Лекция 7. Бинарные кучи. Пирамидальная сортировка
Лекция 7. Бинарные кучи. Пирамидальная сортировкаЛекция 7. Бинарные кучи. Пирамидальная сортировка
Лекция 7. Бинарные кучи. Пирамидальная сортировкаMikhail Kurnosov
 

Mehr von Mikhail Kurnosov (20)

Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)
 
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Векторизация кода (семинар 3)
Векторизация кода (семинар 3)
 
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
 
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
 
Лекция 5. B-деревья (B-trees, k-way merge sort)
Лекция 5. B-деревья (B-trees, k-way merge sort)Лекция 5. B-деревья (B-trees, k-way merge sort)
Лекция 5. B-деревья (B-trees, k-way merge sort)
 
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
 
Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)
 
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
 
Лекция 3. АВЛ-деревья (AVL trees)
Лекция 3. АВЛ-деревья (AVL trees)Лекция 3. АВЛ-деревья (AVL trees)
Лекция 3. АВЛ-деревья (AVL trees)
 
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
 
Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)
 
Лекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовЛекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмов
 
Лекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиЛекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимости
 
Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)
 
Лекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графеЛекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графе
 
Семинар 8. Параллельное программирование на MPI (часть 1)
Семинар 8. Параллельное программирование на MPI (часть 1)Семинар 8. Параллельное программирование на MPI (часть 1)
Семинар 8. Параллельное программирование на MPI (часть 1)
 
Лекция 8. Графы. Обходы графов
Лекция 8. Графы. Обходы графовЛекция 8. Графы. Обходы графов
Лекция 8. Графы. Обходы графов
 
Лекция 7. Бинарные кучи. Пирамидальная сортировка
Лекция 7. Бинарные кучи. Пирамидальная сортировкаЛекция 7. Бинарные кучи. Пирамидальная сортировка
Лекция 7. Бинарные кучи. Пирамидальная сортировка
 

Лекция 6. Стандарт OpenMP

  • 1. КурносовМихаил Георгиевич E-mail: mkurnosov@gmail.com WWW: www.mkurnosov.net Курс “Высокопроизводительные вычислительные системы” Сибирский государственный университет телекоммуникаций и информатики (Новосибирск) Осенний семестр, 2014 Лекция 6Стандарт OpenMP
  • 2. Программный инструментарий 2 Hardware (Multi-core processors, SMP/NUMA) Kernel thread Process/thread scheduler Системные вызовы (System calls) POSIX Threads Apple OS X Cocoa, Pthreads Уровень ядра (Kernel space) Операционная система (Operating System) GNU/Linux, Microsoft Windows, Apple OS X, IBM AIX, Oracle Solaris, … Kernel thread Kernel thread … Уровень пользователя (User space) Системные библиотеки(System libraries) Thread Thread Thread Thread … Win32 API/.NET Threads Thread Thread Thread Thread Kernel thread Kernel thread Kernel thread Kernel thread Kernel thread Intel Threading Building Blocks (TBB) Microsoft Concurrency Runtime Apple Grand Central Dispatch Boost Threads Qthread, MassiveThreads Прикладные библиотеки Языки программирования OpenMP(C/C++/Fortran) Intel CilkPlus С++11 Threads C11 Threads C# Threads Java Threads ErlangThreads Haskell Threads
  • 3. Стандарт OpenMP 3 OpenMP(OpenMulti-Processing) –стандарт, определяющий набор директив компилятора, библиотечных процедур и переменных среды окружения для создания многопоточных программ Разрабатывается в рамках OpenMPArchitecture Review Board с 1997 года http://www.openmp.org OpenMP2.5 (2005), OpenMP3.0 (2008), OpenMP3.1 (2011), OpenMP4.0 (2013) Требуется поддержка со стороны компилятора
  • 4. OpenMP 4 Compiler Information GNU GCC Option:–fopenmpgcc4.2 –OpenMP2.5, gcc4.4 –OpenMP3.0, gcc4.7 –OpenMP3.1 gcc4.9 –OpenMP4.0 Clang(LLVM) OpenMP3.1 Clang + Intel OpenMPRTL http://clang-omp.github.io/ IntelC/C++, Fortran OpenMP3.1 Option: –Qopenmp,–openmp Oracle Solaris Studio C/C++/Fortran OpenMP3.1 Option: –xopenmp MicrosoftVisual Studio 2012 C++ Option: /openmp OpenMP2.0 only Other compilers: IBM XL, PathScale, PGI, AbsoftPro, … http://openmp.org/wp/openmp-compilers/
  • 5. Структура OpenMP-программы 5 Программа представляется в виде последовательных участков кода (serial code) и параллельных регионов (parallel region) Каждый поток имеет номер: 0, 1, 2, … Главный поток (master) имеет номер 0 Память процессаявляется общей для всех потоков OpenMPреализует динамическое управление потоками (task parallelism) OpenMP: data parallelism + task parallelism 0 0 1 2 0 1 0 Барьерная синхронизация
  • 6. Пример OpenMP-программы 6 #include <omp.h> intmain() { #pragma ompparallel { printf("Thread %dn", omp_get_thread_num()); } return0; }
  • 7. Компиляция OpenMP-программы 7 $ gcc–fopenmp–o prog./prog.c $ ./prog Thread 0 Thread 1 Thread 3 Thread 2 $ export OMP_NUM_THREADS=2 $ ./prog Thread 0 Thread 1 По умолчанию количество потоков = количеству логических процессоров в системе
  • 8. Пример OpenMP-программы 8 #include <omp.h> intmain() { #pragma ompparallel { #ifdef_OPENMP printf("Thread %dn", omp_get_thread_num()); #endif } return0; }
  • 9. Компиляция OpenMP-программы 9 $ g++ -Wall -fopenmp-o hello ./hello.cpp $ ./hello Hello, OpenMPWorld! Hello, OpenMPWorld! Hello, OpenMPWorld! Hello, OpenMPWorld! $ g++ -Wall -o hello ./hello.cpp ./hello.cpp:5:0: warning: ignoring #pragma ompparallel [-Wunknown-pragmas] $ ./hello Hello, OpenMPWorld!
  • 10. Синтаксис директив OpenMP 10 Языки С/C++ #pragma ompdirective-name[clause[ [,] clause]...] new-line#pragmaompparallel Fortransentinel directive-name[clause[[,] clause]...] !$ompparallel Создание потоков Распределение вычислений между потоками Управление пространством видимости переменных Синхронизация потоков …
  • 11. Создание потоков(parallel) 11 #pragma ompparallel { /* Этот код выполняется всеми потоками */ } #pragma ompparallel if (expr) { /* Код выполняется потоками если expr= true */ } #pragma ompparallel num_threads(n / 2) { /* Создается n / 2 потоков*/ } На выходе из параллельного региона осуществляется барьерная синхронизация –все потоки ждут последнего
  • 12. Создание потоков(sections) 12 #pragma ompparallel sections { #pragma ompsection { /* Код потока 0 */ } #pragma ompsection { /* Код потока 1 */ } } При любых условиях выполняется фиксированное количество потоков (по количеству секций)
  • 13. Функции runtime-библиотеки 13 intomp_get_thread_num() –возвращает номер текущего потока intomp_get_num_threads() –возвращает количество потоков в параллельном регионе void omp_set_num_threads(intn) double omp_get_wtime()
  • 14. Директиваmaster 14 #pragma ompparallel { /* Этот код выполняется всеми потоками */ #pragma ompmaster { /* Код выполняется только потоком 0 */ } /* Этот код выполняется всеми потоками */ }
  • 15. Директиваsingle 15 #pragma ompparallel { /* Этот код выполняется всеми потоками */ #pragma ompsingle { /* Код выполняется только одним потоком */ } /* Этот код выполняется всеми потоками */ }
  • 16. Директиваfor(data parallelism) 16 #define N 13 #pragma ompparallel { #pragma ompfor for(i = 0; i < N; i++) { printf("Thread %d i = %dn", omp_get_thread_num(), i); } } Итерации цикла распределяются между потоками 0 1 2 3 4 5 6 7 8 9 10 11 12 i: Thread 0 Thread 1 Thread 2 Thread 3
  • 17. Директива for 17 $ OMP_NUM_THREADS=4 ./prog Thread 2 i = 7 Thread 2 i = 8 Thread 2 i = 9 Thread 0 i = 0 Thread 0 i = 1 Thread 0 i = 2 Thread 3 i = 10 Thread 3 i = 11 Thread 3 i = 12 Thread 0 i = 3 Thread 1 i = 4 Thread 1 i = 5 Thread 1 i = 6
  • 18. Алгоритмы распределения итераций 18 #define N 13 #pragma ompparallel { #pragma ompfor schedule(static, 2) for(i = 0; i < N; i++) { printf("Thread %d i = %dn", omp_get_thread_num(), i); } } 0 1 2 3 4 5 6 7 8 9 10 11 12 i: Итерации цикла распределяются циклически (round-robin) блоками по 2 итерации T0 T1 T2 T3 T0 T1 T2
  • 19. Алгоритмы распределения итераций 19 $ OMP_NUM_THREADS=4 ./prog Thread 0 i = 0 Thread 0 i = 1 Thread 0 i = 8 Thread 0 i = 9 Thread 1 i = 2 Thread 1 i = 3 Thread 1 i = 10 Thread 1 i = 11 Thread 3 i = 6 Thread 3 i = 7 Thread 2 i = 4 Thread 2 i = 5 Thread 2 i = 12
  • 20. Алгоритм Описание static, m Цикл делится на блоки поmитераций (до выполнения),которые распределяются по потокам dynamic, m Цикл делится на блоки поm итераций. При выполнении блока из mитераций поток выбирает следующий блок из общего пула guided, m Блоки выделяются динамически. При каждом запросе размер блока уменьшается экспоненциальнодо m runtime Алгоритм задается пользователем через переменную среды OMP_SCHEDULE Алгоритмы распределения итераций 20
  • 21. Директиваfor(ordered) 21 #define N 7 #pragma ompparallel { #pragma ompfor ordered for(i = 0; i < N; i++) { #pragma ompordered printf("Thread %d i = %dn", omp_get_thread_num(), i); } } Директива ordered организует последовательное выполнение итераций (i= 0, 1, …)–синхронизация Поток с i= kожидает пока потоки сi = k–1, k–2, … не выполнятсвои итерации
  • 22. Директива for(ordered) 22 $ OMP_NUM_THREADS=4 ./prog Thread 0 i = 0 Thread 0 i = 1 Thread 1 i = 2 Thread 1 i = 3 Thread 2 i = 4 Thread 2 i = 5 Thread 3 i = 6
  • 23. Директиваfor(nowait) 23 #define N 7 #pragma ompparallel { #pragma ompfor nowait for(i = 0; i < N; i++) { printf("Thread %d i = %dn", omp_get_thread_num(), i); } } По окончанию цикла потоки не выполняют барьерную синхронизацию Конструкция nowaitприменима и к директиве sections
  • 24. Директиваfor (collapse) 24 #define N 3 #define M 4 #pragma ompparallel { #pragma ompfor collapse(2) for (i = 0; i < N; i++) { for (j = 0; j < M; j++) printf("Thread %d i = %dn", omp_get_thread_num(), i); } } сollapse(n)объединяет пространство итераций nциклов в одно 0 1 2 0 1 2 3 i: j: 0,0 0,1 0,2 0,3 1,0 1,1 1,2 1,3 2,0 2,1 2,2 2,3 T0 + T1 T2 T3
  • 25. Директива for (collapse) 25 $ OMP_NUM_THREADS=4 ./prog Thread 2 i = 1 Thread 2 i = 1 Thread 2 i = 2 Thread 0 i = 0 Thread 0 i = 0 Thread 0 i = 0 Thread 3 i = 2 Thread 3 i = 2 Thread 3 i = 2 Thread 1 i = 0 Thread 1 i = 1 Thread 1 i = 1
  • 26. #include <iostream> #include <vector> intmain() { std::vector<int> vec(1000); std::fill(vec.begin(), vec.end(), 1); intcounter = 0; #pragma ompparallel for for(std::vector<int>::size_typei= 0; i< vec.size(); i++) { if(vec[i] > 0) { counter++; } } std::cout<< "Counter = "<< counter << std::endl; return0; } Ошибки в многопоточных программах 26
  • 27. Ошибки в многопоточных программах 27 $ g++ –fopenmp–o ompprog./ompprog.cpp $ ./omprog Counter = 381 $ ./omprog Counter = 909 $ ./omprog Counter = 398 На каждом запуске итоговое значение Counter разное! Правильный результат Counter = 1000
  • 28. #include <iostream> #include <vector> intmain() { std::vector<int> vec(1000); std::fill(vec.begin(), vec.end(), 1); intcounter = 0; #pragma ompparallel for for(std::vector<int>::size_typei= 0; i< vec.size(); i++) { if(vec[i] > 0) { counter++; } } std::cout<< "Counter = "<< counter << std::endl; return0; } Ошибки в многопоточных программах 28 Потоки осуществляют конкурентный доступ к переменной counter – одновременно читают её и записывают
  • 29. Thread 0 Thread 1 Memory(counter) 0 movl[counter], %eax ← 0 incl%eax 0 movl%eax, [counter] → 1 movl[counter], %eax ← 1 incl%eax 1 movl%eax, [counter] → 2 Состояние гонки (Race condition, data race) 29 #pragma ompparallel { counter++; } movl[counter], %eax incl%eax movl%eax, [counter] C++ Идеальнаяпоследовательность выполнения инструкций 2-х потоков counter= 2
  • 30. Thread 0 Thread 1 Memory(counter) 0 movl[counter], %eax ← 0 incl%eax movl[counter], %eax ← 0 movl%eax, [counter] incl%eax → 1 movl%eax, [counter] → 1 1 Состояние гонки (Race condition, data race) 30 movl[counter], %eax incl%eax movl%eax, [counter] C++ Возможнаяпоследовательность выполнения инструкций 2-х потоков counter=1 Error: Data race #pragma ompparallel { counter++; }
  • 31. Состояние гонки (Race condition, data race) 31 Состояние гонки (Race condition, data race) – это состояние программы, в которой несколько потоков одновременно конкурируют за доступ к общей структуре данных (для чтения/записи) Порядок выполнения потоков заранеене известен – носит случайный характер Планировщик динамически распределяет процессорное время учитывая текущую загруженность процессорных ядер, а нагрузку (потоки, процессы) создают пользователи, поведение которых носит случайных характер Состояние гонки данных (Race condition, data race) трудно обнаруживается в программах и воспроизводится в тестах Состояние гонки данных (Race condition, data race)– это типичный пример Гейзенбага(Heisenbug)
  • 32. Обнаружение состояния гонки (Data race) 32 Динамические анализаторы ValgrindHelgrind, DRD Intel Thread Checker Oracle Studio Thread Analyzer Java ThreadSanitizer Java Chord Статические анализаторы кода PVS-Studio (viva64) …
  • 33. ==8238== Helgrind, a thread error detector ==8238== Copyright (C) 2007-2012, and GNU GPL'd, by OpenWorksLLP et al. ==8238== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==8238== Command: ./ompprogreport ... ==8266== ---------------------------------------------------------------- ==8266== Possible data race during write of size 4 at 0x7FEFFD358 by thread #3 ==8266== Locks held: none ==8266== at 0x400E6E: main._omp_fn.0 (ompprog.cpp:14) ==8266== by 0x3F84A08389: ??? (in /usr/lib64/libgomp.so.1.0.0) ==8266== by 0x4A0A245: ??? (in /usr/lib64/valgrind/vgpreload_helgrind-amd64-linux.so) ==8266== by 0x34CFA07C52: start_thread(in /usr/lib64/libpthread-2.17.so) ==8266== by 0x34CF2F5E1C: clone (in /usr/lib64/libc-2.17.so) ==8266== ==8266== This conflicts with a previous write of size 4 by thread #1 ==8266== Locks held: none ==8266== at 0x400E6E: main._omp_fn.0 (ompprog.cpp:14) ==8266== by 0x400CE8: main (ompprog.cpp:11)... ValgrindHelgrind 33 $ g++ -fopenmp-o ompprog./ompprog.cpp $ valgrind--tool=helgrind./ompprog
  • 34. Директивы синхронизации 34 Директивы синхронизации позволяют управлять порядком выполнения заданных участков кода потоками #pragma ompcritical #pragma ompatomic #pragma ompordered #pragma ompbarrier
  • 35. #pragma ompparallel for private(v) for(i = 0; i < n; i++) { v = fun(a[i]); #pragma ompcritical { sum += v; } } Критические секции 35
  • 36. #pragma ompparallel for private(v) for(i = 0; i < n; i++) { v = fun(a[i]); #pragma ompcritical { sum += v; } } Критическая секция (Critical section)–участок кода в многопоточной программе, выполняемый всеми потоками последовательно Критические секции снижают степень параллелизма Критические секции 36
  • 37. Управление видимостью переменных 37 private(list) –во всех потоках создаются локальные копиипеременных (начальное значение) firstprivate(list) –во всех потоках создаются локальные копии переменных, которые инициализируются их значениями до входа в параллельный регион lastprivate(list) –во всех потоках создаются локальные копии переменных. По окончанию работы всех потоков локальная переменная вне параллельного региона обновляется значением этой переменной одного из потоков shared(list) –переменные являются общими для всех потоков threadprivate(list)
  • 38. Атомарные операции 38 #pragma ompparallel for private(v) for(i = 0; i < n; i++) { v = fun(a[i]); #pragma ompatomic sum += v; }
  • 39. Атомарные операции 39 #pragma ompparallel for private(v) for(i = 0; i < n; i++) { v = fun(a[i]); #pragma ompatomic sum += v; } Атомарные операции “легче”критических секций (не используют блокировки) Lock-free algorithms & data structures
  • 40. Параллельная редукция 40 #pragma ompparallel for reduction(+:sum) for(i = 0; i < n; i++) { sum = sum + fun(a[i]); } Операции директивы reduction: +, *, -, &, |, ^, &&, ||, max, min OpenMP4.0поддерживает пользовательские функции редукции
  • 41. Директивы синхронизации 41 #pragma ompparallel { /* Code */ #pragma ompbarrier /* Code */ } Директива barrierосуществляет ожидание достижения данной точки программы всеми потоками
  • 42. #pragma ompflush 42 #pragma ompparallel { /* Code */ #pragma ompflush(a, b) /* Code */ } Принудительно обновляет в памяти значения переменных(Memory barrier) Например, в одном потоке выставляем флаг (сигнал к действию) для другого
  • 43. Умножение матриц v1.0 43 #pragma ompparallel { #pragma ompfor for(i = 0; i < N; i++) { for(j = 0; j < N; j++) { for(k = 0; k < N; k++) { c[i][j] = c[i][j] + a[i][k] * b[k][j]; } } } }
  • 44. Умножение матриц v1.0 44 #pragma ompparallel { #pragma ompfor for(i = 0; i < N; i++) { for(j = 0; j < N; j++) { for(k = 0; k < N; k++) { c[i][j] = c[i][j] + a[i][k] * b[k][j]; } } } } Ошибка! Переменные j, k–общие для всех потоков!
  • 45. Умножение матриц v2.0 45 #pragma ompparallel { #pragma ompforshared(a, b, c) private(j, k) for(i = 0; i < N; i++) { for(j = 0; j < N; j++) { for(k = 0; k < N; k++) { c[i][j] = c[i][j] + a[i][k] * b[k][j]; } } } }
  • 46. Пример Primes (sequential code) 46 start = atoi(argv[1]); end = atoi(argv[2]); if((start % 2) == 0 ) start = start + 1; nprimes= 0; if(start <= 2) nprimes++; for(i= start; i<= end; i+= 2) { if(is_prime_number(i)) nprimes++; } Программа подсчитывает количество простых чисел в интервале [start, end]
  • 47. Пример Primes (serial code) 47 intis_prime_number(intnum) { intlimit, factor = 3; limit = (int)(sqrtf((double)num) + 0.5f); while ((factor <= limit) && (num% factor)) factor++; return(factor > limit); }
  • 48. start = atoi(argv[1]); end = atoi(argv[2]); if((start % 2) == 0 ) start = start + 1; nprimes= 0; if(start <= 2) nprimes++; #pragma ompparallel for for(i= start; i<= end; i+= 2) { if(is_prime_number(i)) nprimes++; } Пример Primes (parallel code) 48
  • 49. start = atoi(argv[1]); end = atoi(argv[2]); if((start % 2) == 0 ) start = start + 1; nprimes= 0; if(start <= 2) nprimes++; #pragma ompparallel for for(i= start; i<= end; i+= 2) { if(is_prime_number(i)) nprimes++; } Пример Primes (parallel code) 49 Data race
  • 50. start = atoi(argv[1]); end = atoi(argv[2]); if((start % 2) == 0 ) start = start + 1; nprimes= 0; if(start <= 2) nprimes++; #pragma ompparallel for for(i= start; i<= end; i+= 2) { if(is_prime_number(i)) #pragma ompcritical nprimes++; } Пример Primes (parallel code) 50
  • 51. start = atoi(argv[1]); end = atoi(argv[2]); if((start % 2) == 0 ) start = start + 1; nprimes= 0; if(start <= 2) nprimes++; #pragma ompparallel for for(i= start; i<= end; i+= 2) { if(is_prime_number(i)) #pragma ompcritical nprimes++; } Пример Primes (parallel code) 51 Увеличение счетчика можно реализовать без блокировки (Lock-free algorithm)
  • 52. start = atoi(argv[1]); end = atoi(argv[2]); if((start % 2) == 0 ) start = start + 1; nprimes= 0; if(start <= 2) nprimes++; #pragma ompparallel forreduction(+:nprimes) for(i= start; i<= end; i+= 2) { if(is_prime_number(i)) nprimes++; } Пример Primes (parallel code) 52
  • 53. start = atoi(argv[1]); end = atoi(argv[2]); if((start % 2) == 0 ) start = start + 1; nprimes= 0; if(start <= 2) nprimes++; #pragma ompparallel forreduction(+:nprimes) for(i= start; i<= end; i+= 2) { if(is_prime_number(i)) nprimes++; } Пример Primes (parallel code) 53 Время выполнения is_prime_number(i) зависит отзначения i
  • 54. #pragma ompparallel forreduction(+:nprimes) for(i= start; i<= end; i+= 2) { if(is_prime_number(i)) nprimes++; } Пример Primes (parallel code) 54 Поток 0 Поток 1 Поток 2 Поток 3 Поток 4 Время выполнения потоков различно! Load Imbalance
  • 55. Пример Primes (parallel code) 55 start = atoi(argv[1]); end = atoi(argv[2]); if((start % 2) == 0 ) start = start + 1; nprimes= 0; if(start <= 2) nprimes++; #pragma ompparallel for schedule(static, 1) reduction(+:nprimes) for(i = start; i <= end; i += 2) { if(is_prime_number(i)) nprimes++; }
  • 56. Вычисление числа 흅 56 0,00 0,50 1,00 1,50 2,00 2,50 3,00 3,50 4,00 4,50 0,00 0,10 0,20 0,30 0,40 0,50 0,60 0,70 0,80 0,90 휋 = 0 1 4 1 + 푥2 푑푥 휋 ≈ ℎ 푖=1 푛 4 1 + (ℎ(푖 − 0.5))2 ℎ = 1 푛
  • 57. Вычисление числа 흅 57 0,00 0,50 1,00 1,50 2,00 2,50 3,00 3,50 4,00 4,50 0,00 0,10 0,20 0,30 0,40 0,50 0,60 0,70 0,80 0,90 휋 = 0 1 4 1 + 푥2 푑푥 휋 ≈ ℎ 푖=1 푛 4 1 + (ℎ(푖 − 0.5))2 ℎ = 1 푛 // Последовательная версия int main() { // ... nsteps = 1000000; step = 1.0 / nsteps; sum = 0.0; for (i = 1; i <= nsteps; i++) { x = (i - 0.5) * step; sum = sum + 4.0 / (1.0 + x * x); } pi = step * sum; printf("Pi = %.16fn", pi); return 0; } ℎ = 1 푛
  • 58. Вычисление числа 흅(OpenMP) 58 intmain(intargc, char**argv) { // ... intnthreads= omp_get_max_threads(); doublesumloc[nthreads]; doublesum = 0.0; #pragmaompparallel{ inttid= omp_get_thread_num(); sumloc[tid] = 0.0; #pragmaompfor nowaitfor(inti = 1; i <= nsteps; i++) { doublex = (i-0.5) * step; sumloc[tid] += 4.0 / (1.0 + x * x); } #pragmaompcriticalsum += sumloc[tid]; } doublepi = step * sum; printf("PI is approximately %.16f, Error is %.16fn", pi, fabs(pi -PI25DT)); // ... }
  • 59. Вычисление числа 흅(OpenMP) intmain(intargc, char**argv) { // ... intnthreads= omp_get_max_threads(); doublesumloc[nthreads]; doublesum = 0.0; #pragmaompparallel{ inttid= omp_get_thread_num(); sumloc[tid] = 0.0; #pragmaompfor nowaitfor(inti = 1; i <= nsteps; i++) { doublex = (i-0.5) * step; sumloc[tid] += 4.0 / (1.0 + x * x); } #pragmaompcriticalsum += sumloc[tid]; } doublepi = step * sum; printf("PI is approximately %.16f, Error is %.16fn", pi, fabs(pi -PI25DT)); // ... } Shared memory (RAM) Core 0 (Thread 0) Cache Core 1 (Thread 1) Cache MESI (Intel MESIF) cache coherency protocol sumloc[0], sumloc[1], … могут попасть в одну строку кеш-памяти сachelineобновляется несколькими потоками – кеширование “отключается” Cacheline sumloc[0] Cacheline sumloc[1] False sharing (ложное разделение)
  • 60. Вычисление числа 흅(OpenMP)v2 60 structthreadparams{ doublesum; doublepadding[7]; // Padding for cachelinesize (64 bytes) }; intmain(intargc, char**argv) { // ... threadparamssumloc[nthreads] __attribute__ ((aligned(64))); //double sumloc[nthreads* 8]; doublesum = 0.0; #pragmaompparallel num_threads(nthreads) { inttid= omp_get_thread_num(); sumloc[tid].sum = 0.0; #pragmaompfornowaitfor(inti = 1; i <= nsteps; i++) { doublex = (i-0.5) * step; sumloc[tid].sum += 4.0 / (1.0 + x * x); } #pragmaompcriticalsum += sumloc[tid].sum; } // ... } Avoiding and Identifying False Sharing Among Threads // http://software.intel.com/en-us/articles/avoiding-and-identifying-false-sharing-among-threads
  • 61. Вычисление числа 흅(OpenMP)v2.1 61 // ... doublesum = 0.0; #pragmaompparallel num_threads(nthreads) { doublesumloc= 0.0; // Избавились от массива#pragmaompfornowaitfor(inti = 1; i <= nsteps; i++) { doublex = (i-0.5) * step; sumloc+= 4.0 / (1.0 + x * x); } #pragmaompcriticalsum += sumloc; } doublepi = step * sum; // ...
  • 62. Директива task(OpenMP3.0) 62 intfib(intn) { if(n < 2) returnn; returnfib(n -1) + fib(n -2); } Директива task создает задачу (легковесный поток) Задачи из пула динамически выполняются группой потоков Динамическое распределение задача по потокам осуществляется алгоритмами планирования типа work stealing Задач может быть намного больше количества потоков
  • 63. Директива task(OpenMP3.0) 63 intfib(intn) { intx, y; if(n < 2) returnn; #pragma omptask shared(x, n) x = fib(n -1); #pragma omptask shared(y, n) y = fib(n -2); #pragma omptaskwait returnx + y; } #pragma ompparallel #pragma ompsingle val= fib(n); Каждый рекурсивный вызов –это задача Ожидаем завершение дочерних задач
  • 64. Директива task(OpenMP3.0) 64 fib(1) fib(0) fib(2) fib(3) fib(1) fib(1) fib(0) fib(2) fib(4) Легковесные задачи (tasks) 0 1 2 3 Очереди (деки) задач + пул потоков операционной системы Need tasks Spawn Sync
  • 65. Вложенные параллельные регионы 65 voidlevel2() { #pragmaompparallel sections { #pragmaompsection{printf("L2 1 Thread PID %un", (unsignedint)pthread_self()); } #pragmaompsection{printf("L2 2 Thread PID %un", (unsignedint)pthread_self());} } } voidlevel1() { #pragmaompparallel sections num_threads(2) { #pragmaompsection{printf("L1 1 Thread PID %un", (unsignedint)pthread_self()); level2(); } #pragmaompsection{printf("L1 2 Thread PID %un", (unsignedint)pthread_self()); level2(); } } } intmain() {omp_set_dynamic(0); omp_set_nested(1); level1(); }
  • 66. Вложенные параллельные регионы 66 voidlevel2() { #pragmaompparallel sections { #pragmaompsection{printf("L2 1 Thread PID %un", (unsignedint)pthread_self()); } #pragmaompsection{printf("L2 2 Thread PID %un", (unsignedint)pthread_self());} } } voidlevel1() { #pragmaompparallel sections num_threads(2) { #pragmaompsection{printf("L1 1 Thread PID %un", (unsignedint)pthread_self()); level2(); } #pragmaompsection{printf("L1 2 Thread PID %un", (unsignedint)pthread_self()); level2(); } } } intmain() {omp_set_dynamic(0); omp_set_nested(1); level1(); } Section 2 Section 1 Section 1 Section 2 PID = 210 PID = 100 PID = 100 main() sections num_threads(2) Количество потоков8 (1 + 1 + 3 + 3) Поток, создавший параллельный регион, входит в состав новой группы (создается n–1 потоков)
  • 67. Рекурсивный параллелизм(QuickSort) 67 voidpartition(int*v, int& i, int& j, intlow, inthigh) { i= low; j = high; intpivot = v[(low + high) / 2]; do{ while(v[i] < pivot) i++; while(v[j] > pivot) j--; if(i<= j) { std::swap(v[i], v[j]); i++; j--; } } while(i<= j); } voidquicksort(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); if(low < j) quicksort(v, low, j); if(i< high) quicksort(v, i, high); }
  • 68. QuickSortv1 (nested sections) 68 omp_set_nested(1); // Enable nested parallel regionsvoidquicksort_nested(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); #pragmaompparallel sections num_threads(2) { #pragmaompsection{ if(low < j) quicksort_nested(v, low, j); } #pragmaompsection{ if(i< high) quicksort_nested(v, i, high); } } } Минусы Неограниченная глубина вложенных параллельных регионов Отдельные потоки создаются даже для сортировки коротких отрезков [low, high]
  • 69. QuickSortv2 (max_active_levels) 69 omp_set_nested(1); // Maximum allowed number of nested, active parallel regionsomp_set_max_active_levels(4); voidquicksort_nested(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); #pragmaompparallel sections num_threads(2) { #pragmaompsection{ if(low < j) quicksort_nested(v, low, j); } #pragmaompsection{ if(i< high) quicksort_nested(v, i, high); } } }
  • 70. QuickSortv3 (пороговое значение) 70 omp_set_nested(1); // Enable nested parallel regionsmp_set_max_active_levels(4); // Max. number of nested parallel regionsvoidquicksort_nested(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); if(high -low < threshold|| (j -low < threshold|| high -i< threshold)) { if(low < j) // Sequential executionquicksort_nested(v, low, j); if(i< high) quicksort_nested(v, i, high); } else{ #pragmaompparallel sections num_threads(2) { #pragmaompsection{quicksort_nested(v, low, j); } #pragmaompsection{quicksort_nested(v, i, high); } } } } Короткие интервалы сортируем последовательным алгоритмом Сокращение накладных расходов на создание потоков
  • 71. QuickSortv4 (task) 71 #pragmaompparallel{ #pragmaompsinglequicksort_tasks(array, 0, size -1); } voidquicksort_tasks(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); if(high -low < threshold || (j -low < threshold || high -i< threshold)) { if(low < j) quicksort_tasks(v, low, j); if(i< high) quicksort_tasks(v, i, high); } else{ #pragmaomptask{quicksort_tasks(v, low, j); } quicksort_tasks(v, i, high); } }
  • 72. QuickSortv4 (task + untied) 72 #pragmaompparallel{ #pragmaompsinglequicksort_tasks(array, 0, size -1); } voidquicksort_tasks(int*v, intlow, inthigh) { inti, j; partition(v, i, j, low, high); if(high -low < threshold || (j -low < threshold || high -i< threshold)) { if(low < j) quicksort_tasks(v, low, j); if(i< high) quicksort_tasks(v, i, high); } else{ // Открепить задачу от потока (задачу может выполнять // любой поток) #pragmaomptask untied{quicksort_tasks(v, low, j); } quicksort_tasks(v, i, high); } }
  • 73. Блокировки (locks) 73 Блокировка, мьютекс(lock, mutex)–это объект синхронизации, которыйпозволяет ограничить одновременный доступ потоков к разделяемым ресурсам (реализует взаимное исключение) OpenMP: omp_lock_set/omp_lock_unset POSIX Pthreads: pthread_mutex_lock/pthread_mutex_unlock C++11: std::mutex::lock/std::mutex::unlock C11: mtx_lock/mtx_unlock Блокировка (lock) может быть рекурсивной (вложенной) – один поток может захватывать блокировку несколько раз
  • 74. #include <omp.h> intmain() { std::vector<int> vec(1000); std::fill(vec.begin(), vec.end(), 1); intcounter = 0; omp_lock_tlock; omp_init_lock(&lock); #pragma ompparallel for for (std::vector<int>::size_typei= 0; i< vec.size(); i++) { if (vec[i] > 0) { omp_set_lock(&lock); counter++; omp_unset_lock(&lock); } } omp_destroy_lock(&lock); std::cout<< "Counter = " << counter << std::endl; return0; } Блокировки (locks) 74
  • 75. Взаимная блокировка (Deadlock) 75 Взаимная блокировка (deadlock, тупик)– ситуация когда два и более потока находятся в состоянии бесконечного ожидания ресурсов, захваченных этими потоками Самоблокировка (self deadlock) –ситуация когда поток пытается повторно захватить блокировку, которую уже захватил (deadlock возникает если блокировка не является рекурсивной)
  • 76. voiddeadlock_example() { #pragma ompsections { #pragma ompsection { omp_lock_tlock1, lock2; omp_set_lock(&lock1); omp_set_lock(&lock2); // Code omp_unset_lock(&lock2); omp_unset_lock(&lock1); } #pragma ompsection { omp_lock_tlock1, lock2; omp_set_lock(&lock2); omp_set_lock(&lock1); // Code omp_unset_lock(&lock1); omp_unset_lock(&lock2); } } } Взаимная блокировка (Deadlock) 76 1.T0захватывает Lock1 2.T0 ожидает Lock2 1.T1захватывает Lock2 2.T1 ожидает Lock1
  • 77. OpenMP4.0: Поддержка ускорителей (GPU) 77 sum = 0; #pragma omptarget device(acc0) in(B,C) #pragma ompparallel for reduction(+:sum) for(i=0; i<N; i++) sum += B[i] * C[i] omp_set_default_device() omp_get_default_device() omp_get_num_devices()
  • 78. OpenMP4.0: SIMD-конструкции 78 voidminex(float*a, float*b, float*c, float*d) { #pragma ompparallel for simd for(i= 0; i< N; i++) d[i] = min(distsq(a[i], b[i]), c[i]); } SIMD-конструкции для векторизации циклов (SSE, AVX2, AVX-512, AltiVec, …)
  • 79. OpenMP4.0: Thread Affinity 79 #pragma ompparallel proc_bind(master | close | spread) omp_proc_bind_tomp_get_proc_bind(void) Env. variable OMP_PLACES Thread affinity –привязка потоков к процессорным ядрам exportOMP_NUM_THREADS=16 exportOMP_PLACES=0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15 exportOMP_PROC_BIND=spread,close
  • 80. #pragmaompdeclarereduction(merge: std::vector<int> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end() )) voidschedule(std::vector<int> &v, std::vector<int> &filtered) { #pragma ompparallel for reduction (merge: filtered) for(std:vector<int>::iterator it = v.begin(); it < v.end(); it++) { if(filter(*it)) filtered.push_back(*it); } } OpenMP4.0: user defined reductions 80 #pragma ompdeclare reduction(reduction-identifier : typename-list : combiner) [identity(identity-expr)]
  • 81. Литература 81 ЭхтерШ., Робертс Дж. Многоядерное программирование. –СПб.: Питер, 2010. –316 с. ЭндрюсГ.Р. Основы многопоточного, параллельного и распределенного программирования. –М.: Вильямс, 2003. –512 с. Darryl Gove. Multicore Application Programming: for Windows, Linux, and Oracle Solaris. –Addison-Wesley, 2010. –480 p. Maurice Herlihy, NirShavit. The Art of Multiprocessor Programming. –Morgan Kaufmann, 2008. –528 p. Richard H. Carver,Kuo-Chung Tai. Modern Multithreading : Implementing, Testing, and Debugging Multithreaded Java and C++/Pthreads/Win32 Programs. –Wiley-Interscience, 2005. –480 p. Anthony Williams. C++ Concurrency in Action: Practical Multithreading. – Manning Publications, 2012. –528 p. TräffJ.L. Introduction to Parallel Computing // http://www.par.tuwien.ac.at/teach/WS12/ParComp.html