SlideShare a Scribd company logo
1 of 43
Download to read offline
Семинар 1
Стандарт OpenMP (часть 1)
Михаил Курносов
E-mail: mkurnosov@gmail.com
WWW: www.mkurnosov.net
Цикл семинаров «Основы параллельного программирования»
Институт физики полупроводников им. А. В. Ржанова СО РАН
Новосибирск, 2015 CC-BY
Многопроцессорные системы с общей памятью
 Процессоры SMP-системы имеют одинаковое время доступа к разделяемой памяти:
симметричный, однородный доступ к памяти – Uniform Memory Access (UMA)
 Системная шина (system bus, crossbar) – узкое место, ограничивающее производительность
вычислительного узла (процессоры конкурируют за доступ к ней)
 Проблемы: низкая масштабируемость, обеспечение когерентности (согласованности)
кеш-памяти процессоров и разделяемой памяти
CPU 1
Cache
CPU 2
Cache
CPU N
Cache
I/O
Bus
arbiter
System bus
Shared memory (RAM)
SMP-системы
Многопроцессорные системы с общей памятью
 NUMA (Non-Uniform Memory Architecture) – многопроцессорная вычислительная система
с неоднородным доступом к разделяемой памяти
 Процессоры сгруппированы в NUMA-узлы со своей локальной памятью (NUMA nodes)
 Разное время доступа к локальной памяти NUMA-узла (NUMA-node) и памяти другого узла
 Большая масштабируемость по сравнению с SMP-системами
 Проблемы: обеспечение когерентности кеш-памяти процессоров
NUMA-системы
Local access (fast)
Remote access (slow)
Поток 0
Процессы и потоки
int fun()
{
// …
}
Стек потока 0
Куча (heap)
(динамически выделяемая память: malloc/free)
Область неинициализированных данных (BSS)
(глобальные неинициализированные переменные)
Область инициализированных данных (Data)
(глобальные инициализированные переменные)
// Uninitialized data (BSS)
int sum[100]; // BSS
// Initialized data (Data)
float grid[100][100] = {1.0};
int main()
{
// Local variable (stack)
double s = 0.0;
// Allocate from the heap
float *x = malloc(1000);
// ...
free(x);
}
Поток 0
Процессы и потоки
int fun()
{
// …
}
Поток 1
int fun()
{
// …
}
Поток N-1
int fun()
{
// …
}
…
Стек потока 0
Стек потока 1
Стек потока N - 1
…
Куча (heap)
(динамически выделяемая память: malloc/free)
Область неинициализированных данных (BSS)
(глобальные неинициализированные переменные)
Область инициализированных данных (Data)
(глобальные инициализированные переменные)
// Uninitialized data (BSS)
int sum[100]; // BSS
// Initialized data (Data)
float grid[100][100] = {1.0};
int main()
{
// Local variable (stack)
double s = 0.0;
// Allocate from the heap
float *x = malloc(1000);
// ...
free(x);
}
Средства многопоточного программирования
Hardware (Multi-core processor, SMP/NUMA)
Kernel
thread
Process scheduler
Системные вызовы (System calls)
POSIX Threads Apple OS X Cocoa, Pthreads
Уровень ядра
(Kernel space)
Операционная система
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 Cilk Plus
 С++11 Threads
 C11 Threads
 C# Threads
 Java Threads
 Erlang Threads
 Haskell Threads
OpenMP
pthreads
(glibc)
clone()
(Linux syscall)
Стандарт OpenMP
 OpenMP (Open Multi-Processing) – стандарт, определяющий набор директив
компилятора, библиотечных процедур и переменных среды окружения для
создания многопоточных программ
 Разрабатывается в рамках OpenMP Architecture Review Board с 1997 года
 OpenMP 2.5 (2005), OpenMP 3.0 (2008), OpenMP 3.1 (2011), OpenMP 4.0 (2013)
 http://www.openmp.org
 http://www.openmp.org/mp-documents/OpenMP4.0.0.pdf
 Требуется поддержка со стороны компилятора
Поддержка компиляторами
Compiler Information
GNU GCC
Option: –fopenmp
gcc 4.2 – OpenMP 2.5,
gcc 4.4 – OpenMP 3.0,
gcc 4.7 – OpenMP 3.1
gcc 4.9 – OpenMP 4.0
Clang (LLVM)
OpenMP 3.1
сlang + Intel OpenMP RTL
http://clang-omp.github.io/
Intel C/C++, Fortran
OpenMP 4.0
Option: –Qopenmp, –openmp
Oracle Solaris Studio C/C++/Fortran
OpenMP 4.0
Option: –xopenmp
Microsoft Visual Studio C++
Option: /openmp
OpenMP 2.0 only
Other compilers: IBM XL, PathScale, PGI, Absoft Pro, …
0 1
0
0 1 2
0
Модель выполнения OpenMP-программы
 Динамическое управление потоками в модели Fork-Join:
 Fork – порождение нового потока
 Join – ожидание завершения потока
(объединение потоков управления)
 OpenMP-программа – совокупность
последовательных участков кода (serial code)
и параллельных регионов (parallel region)
 Каждый поток имеет логический номер: 0, 1, 2, …
 Главный поток (master) имеет номер 0
 Параллельные регионы могут быть вложенными
Parallel
region
Parallel
region
Barrier
Barrier
Hello, World
#include <stdio.h>
#include <omp.h>
int main(int argc, char **argv)
{
#pragma omp parallel /* <-- Fork */
{
printf("Hello, multithreaded world: thread %d of %dn",
omp_get_thread_num(), omp_get_num_threads());
} /* <-- Barrier & join */
return 0;
}
Компиляция и запуск OpenMP-программы
$ gcc –fopenmp –o hello ./hello.c
$ ./hello
Hello, multithreaded world: thread 0 of 4
Hello, multithreaded world: thread 1 of 4
Hello, multithreaded world: thread 3 of 4
Hello, multithreaded world: thread 2 of 4
 По умолчанию количество потоков в параллельном регионе равно числу
логических процессоров в системе
 Порядок выполнения потоков заранее неизвестен – определяется
планировщиком операционной системы
Указание числа потоков в параллельных регионах
$ export OMP_NUM_THREADS=8
$ ./hello
Hello, multithreaded world: thread 1 of 8
Hello, multithreaded world: thread 2 of 8
Hello, multithreaded world: thread 3 of 8
Hello, multithreaded world: thread 0 of 8
Hello, multithreaded world: thread 4 of 8
Hello, multithreaded world: thread 5 of 8
Hello, multithreaded world: thread 6 of 8
Hello, multithreaded world: thread 7 of 8
Задание числа потоков в параллельном регионе
#include <stdio.h>
#include <omp.h>
int main(int argc, char **argv)
{
#pragma omp parallel num_threads(6)
{
printf("Hello, multithreaded world: thread %d of %dn",
omp_get_thread_num(), omp_get_num_threads());
}
return 0;
}
Задание числа потоков в параллельном регионе
$ export OMP_NUM_THREADS=8
$ ./hello
Hello, multithreaded world: thread 2 of 6
Hello, multithreaded world: thread 3 of 6
Hello, multithreaded world: thread 1 of 6
Hello, multithreaded world: thread 0 of 6
Hello, multithreaded world: thread 4 of 6
Hello, multithreaded world: thread 5 of 6
 Директива num_threads имеет приоритет над значением переменной среды
окружения OMP_NUM_THREADS
Список потоков процесса
#include <stdio.h>
#include <omp.h>
#include <time.h>
int main(int argc, char **argv)
{
#pragma omp parallel num_threads(6)
{
printf("Hello, multithreaded world: thread %d of %dn",
omp_get_thread_num(), omp_get_num_threads());
/* Sleep for 30 seconds */
nanosleep(&(struct timespec){.tv_sec = 30}, NULL);
}
return 0;
}
Список потоков процесса
$ ./hello &
$ ps -eLo pid,tid,psr,args | grep hello
6157 6157 0 ./hello
6157 6158 1 ./hello
6157 6159 0 ./hello
6157 6160 1 ./hello
6157 6161 0 ./hello
6157 6162 1 ./hello
6165 6165 2 grep hello
 Номер процесса (PID)
 Номер потока (TID)
 Логический процессор (PSR)
 Название исполняемого файла
 Информация о логических процессорах системы:
 /proc/cpuinfo
 /sys/devices/system/cpu
Умножение матрицы на вектор (DGEMV)
𝐴 =
𝑎11 𝑎12 … 𝑎1𝑛
𝑎21 𝑎22 … 𝑎2𝑛
… … … …
𝑎 𝑚1 𝑎 𝑚2 … 𝑎 𝑚𝑛
𝐵 =
𝑏1
𝑏2
…
𝑏 𝑛
𝑐𝑖 =
𝑗=1
𝑛
𝑎𝑖𝑗 ∙ 𝑏𝑗 , 𝑖 = 1,2, … , 𝑚.
𝑪 𝒎×𝟏 = 𝑨 𝒎×𝒏 ∙ 𝑩 𝒏×𝟏
 Требуется вычислить произведение прямоугольной матрицы A размера 𝑚 × 𝑛
на вектор-столбец B размера 𝑚 × 1 (BLAS Level 2, DGEMV)
𝐶 =
𝑐1
𝑐2
…
𝑐 𝑚
DGEMV: последовательная версия
/*
* matrix_vector_product: Compute matrix-vector product c[m] = a[m][n] * b[n]
*/
void matrix_vector_product(double *a, double *b, double *c, int m, int n)
{
for (int i = 0; i < m; i++) {
c[i] = 0.0;
for (int j = 0; j < n; j++)
c[i] += a[i * n + j] * b[j];
}
}
𝑐𝑖 =
𝑗=1
𝑛
𝑎𝑖𝑗 ∙ 𝑏𝑗 , 𝑖 = 1,2, … , 𝑚.
DGEMV: последовательная версия
void run_serial()
{
double *a, *b, *c;
a = xmalloc(sizeof(*a) * m * n);
b = xmalloc(sizeof(*b) * n);
c = xmalloc(sizeof(*c) * m);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
a[i * n + j] = i + j;
}
for (int j = 0; j < n; j++)
b[j] = j;
double t = wtime();
matrix_vector_product(a, b, c, m, n);
t = wtime() - t;
printf("Elapsed time (serial): %.6f sec.n", t);
free(a);
free(b);
free(c);
}
DGEMV: параллельная версия
A[m][n] C[m]
B[n]
for (int i = 0; i < m; i++) {
c[i] = 0.0;
for (int j = 0; j < n; j++)
c[i] += a[i * n + j] * b[j];
}
Требования к параллельному алгоритму
 Максимальная загрузка потоков вычислениями
 Минимум совместно используемых ячеек памяти –
независимые области данных
DGEMV: параллельная версия
A[m][n] C[m]
B[n]
Распараллеливание внешнего цикла
 Каждом потоку выделяется часть
строк матрицы A
Поток 1
Поток 2
Поток 3
for (int i = 0; i < m; i++) {
c[i] = 0.0;
for (int j = 0; j < n; j++)
c[i] += a[i * n + j] * b[j];
}
Поток 4
DGEMV: параллельная версия
/* matrix_vector_product_omp: Compute matrix-vector product c[m] = a[m][n] * b[n] */
void matrix_vector_product_omp(double *a, double *b, double *c, int m, int n)
{
#pragma omp parallel
{
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
int items_per_thread = m / nthreads;
int lb = threadid * items_per_thread;
int ub = (threadid == nthreads - 1) ? (m - 1) : (lb + items_per_thread - 1);
for (int i = lb; i <= ub; i++) {
c[i] = 0.0;
for (int j = 0; j < n; j++)
c[i] += a[i * n + j] * b[j];
}
}
}
A[m][n] C[m]
lb
ub
DGEMV: параллельная версия
void run_parallel()
{
double *a, *b, *c;
// Allocate memory for 2-d array a[m, n]
a = xmalloc(sizeof(*a) * m * n);
b = xmalloc(sizeof(*b) * n);
c = xmalloc(sizeof(*c) * m);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
a[i * n + j] = i + j;
}
for (int j = 0; j < n; j++)
b[j] = j;
double t = wtime();
matrix_vector_product_omp(a, b, c, m, n);
t = wtime() - t;
printf("Elapsed time (parallel): %.6f sec.n", t);
free(a);
free(b);
free(c);
}
DGEMV: параллельная версия
int main(int argc, char **argv)
{
printf("Matrix-vector product (c[m] = a[m, n] * b[n]; m = %d, n = %d)n", m, n);
printf("Memory used: %" PRIu64 " MiBn", ((m * n + m + n) * sizeof(double)) >> 20);
run_serial();
run_parallel();
return 0;
}
Анализ эффективности OpenMP-версии
 Введем обозначения:
 𝑻(𝒏) – время выполнения последовательной программы (serial program) при заданном
размере n входных данных
 𝑻 𝒑(𝒏, 𝒑) – время выполнения параллельной программы (parallel program) на p процессорах
при заданном размере n входных данных
 Коэффициент Sp(n) ускорения параллельной программ (Speedup):
𝑺 𝒑 𝒏 =
𝑻(𝒏)
𝑻 𝒑(𝒏)
 Как правило
𝑆 𝑝 𝑛 ≤ 𝑝
 Цель распараллеливания –
достичь линейного ускорения на наибольшем числе процессоров: 𝑆 𝑝 𝑛 ≥ 𝑐 ∙ 𝑝, при 𝑝 → ∞ и 𝑐 > 0
Во сколько раз параллельная
программа выполняется на p
процессорах быстрее
последовательной программы
при обработке одних и тех же
данных размера n
Анализ эффективности OpenMP-версии
M = N
Количество потоков
2 4 6 8
T1 T2 S2 T4 S4 T6 S6 T8 S8
20 000
(~ 3 GiB)
0.73 0.34 2.12 0.24 3.11 0.23 3.14 0.25 2.84
40 000
(~ 12 GiB)
2.98 1.30 2.29 0.95 3.11 0.91 3.21 0.87 3.38
49 000
(~ 18 GiB)
1.23 3.69
0
1
2
3
4
5
6
7
8
9
2 4 6 8
Sp
p
Linear
M = 20 000
M = 40 000
Вычислительный узел кластера Oak (oak.cpct.sibsutis.ru):
 System board: Intel 5520UR
 8 ядер – два Intel Quad Xeon E5620 (2.4 GHz)
 24 GiB RAM – 6 x 4GB DDR3 1067 MHz
 CentOS 6.5 x86_64, GCC 4.4.7
 Ключи компиляции: -std=c99 -Wall -O2 -fopenmp
Низкая масштабируемость!
Причины ?
DGEMV: конкуренция за доступ к памяти
/* matrix_vector_product_omp: Compute matrix-vector product c[m] = a[m][n] * b[n] */
void matrix_vector_product_omp(double *a, double *b, double *c, int m, int n)
{
#pragma omp parallel
{
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
int items_per_thread = m / nthreads;
int lb = threadid * items_per_thread;
int ub = (threadid == nthreads - 1) ? (m - 1) : (lb + items_per_thread - 1);
for (int i = lb; i <= ub; i++) {
c[i] = 0.0; // Store – запись в память
for (int j = 0; j < n; j++)
// Memory ops: Load c[i], Load a[i][j], Load b[j], Store c[i]
c[i] += a[i * n + j] * b[j];
}
}
}
 DGEMV – data intensive application
 Конкуренция за доступ к контролеру памяти
 ALU ядер загружены незначительно
Конфигурация узла кластера Oak
Вычислительный узел кластера Oak (oak.cpct.sibsutis.ru):
 System board: Intel 5520UR (NUMA-система)
 Процессоры связаны шиной QPI Link: 5.86 GT/s
 24 GiB RAM – 6 x 4GB DDR3 1067 MHz
$ numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6
node 0 size: 12224 MB
node 0 free: 11443 MB
node 1 cpus: 1 3 5 7
node 1 size: 12288 MB
node 1 free: 11837 MB
node distances:
node 0 1
0: 10 21
1: 21 10
http://download.intel.com/support/motherboards/server/s5520ur/sb/e44031012_s5520ur_s5520urt_tps_r1_9.pdf
CPU0 CPU1
DRAMDRAM
QPI
QPI QPI
NUMA-node 0 NUMA-node 1
Конфигурация узла кластера Oak
Вычислительный узел кластера Oak (oak.cpct.sibsutis.ru):
 System board: Intel 5520UR (NUMA-система)
 Процессоры связаны шиной QPI Link: 5.86 GT/s
 24 GiB RAM – 6 x 4GB DDR3 1067 MHz
$ numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6
node 0 size: 12224 MB
node 0 free: 11443 MB
node 1 cpus: 1 3 5 7
node 1 size: 12288 MB
node 1 free: 11837 MB
node distances:
node 0 1
0: 10 21
1: 21 10
http://download.intel.com/support/motherboards/server/s5520ur/sb/e44031012_s5520ur_s5520urt_tps_r1_9.pdf
CPU0 CPU1
DRAMDRAM
QPI
QPI QPI
NUMA-node 0 NUMA-node 1
А на каком NUMA-узле (узлах)
размещена матрица A и векторы B, С?
Выделение памяти потокам в GNU/Linux
 Страница памяти выделяется с NUMA-узла того потока, который первый к ней обратился
(first-touch policy)
 Данные желательно инициализировать теми потоками, которые будут с ними работать
void run_parallel()
{
double *a, *b, *c;
// Allocate memory for 2-d array a[m, n]
a = xmalloc(sizeof(*a) * m * n);
b = xmalloc(sizeof(*b) * n);
c = xmalloc(sizeof(*c) * m);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
a[i * n + j] = i + j;
}
for (int j = 0; j < n; j++)
b[j] = j;
С1 С2 С3 С4
RAM (12 GiB)
NUMA-node 0
С1 С2 С3 С4
RAM (12 GiB)
NUMA-node 1
Bus
Thread 0
 Поток 0 запрашивает выделение памяти под
массивы
 Пока хватает памяти, ядро выделяет страницы
с NUMA-узла 0, затем с NUMA-узла 1
a[][] b c
Выделение памяти потокам в GNU/Linux
 Страница памяти выделяется с NUMA-узла того потока, который первый к ней обратился
(first-touch policy)
 Данные желательно инициализировать теми потоками, которые будут с ними работать
void run_parallel()
{
double *a, *b, *c;
// Allocate memory for 2-d array a[m, n]
a = xmalloc(sizeof(*a) * m * n);
b = xmalloc(sizeof(*b) * n);
c = xmalloc(sizeof(*c) * m);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
a[i * n + j] = i + j;
}
for (int j = 0; j < n; j++)
b[j] = j;
С1 С2 С3 С4
RAM (12 GiB)
NUMA-node 0
С1 С2 С3 С4
RAM (12 GiB)
NUMA-node 1
Bus
Thread 0
 Обращение к массивам из потоков
NUMA-узла 1 будет идти через
межпроцессорную шину в память узла 0
a[][] b c
Thread 2Thread 1 Thread 3
Параллельная инициализация массивов
void run_parallel()
{
double *a, *b, *c;
// Allocate memory for 2-d array a[m, n]
a = xmalloc(sizeof(*a) * m * n);
b = xmalloc(sizeof(*b) * n);
c = xmalloc(sizeof(*c) * m);
#pragma omp parallel
{
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
int items_per_thread = m / nthreads;
int lb = threadid * items_per_thread;
int ub = (threadid == nthreads - 1) ? (m - 1) : (lb + items_per_thread - 1);
for (int i = lb; i <= ub; i++) {
for (int j = 0; j < n; j++)
a[i * n + j] = i + j;
c[i] = 0.0;
}
}
for (int j = 0; j < n; j++)
b[j] = j;
/* ... */
}
Анализ эффективности OpenMP-версии (2)
M = N
Количество потоков
2 4 6 8
T1 T2 S2 T4 S4 T6 S6 T8 S8
20 000
(~ 3 GiB)
0.73 0.34 2.12 0.24 3.11 0.23 3.14 0.25 2.84
40 000
(~ 12 GiB)
2.98 1.30 2.29 0.95 3.11 0.91 3.21 0.87 3.38
49 000
(~ 18 GiB)
1.23 3.69
Parallel initialization
40 000
(~ 12 GiB)
2.98 1.22 2.43 0.67 4.41 0.65 4.65 0.54 5.48
49 000
(~ 18 GiB)
0.83 5.41
0
1
2
3
4
5
6
7
8
9
2 4 6 8
Sp
p
Linear
M = 20 000
M = 40 000
Sp
p
Linear
M = 20 000
M = 40 000
Par. init
Суперлинейное ускорение (super-linear speedup): 𝑆 𝑝 𝑛 > 𝑝
Улучшили масштабируемость
Дальнейшие оптимизации:
 Эффективный доступ к кеш-памяти
 Векторизация кода (SSE/AVX)
 …
Задание
 Реализовать многопоточную версию программы умножения матрицы на вектор
с параллельной инициализацией массивов
 Шаблон программы для выполнения задания находится в каталоге task
 На кластере oak примеры находятся в папке /home/pub/parprog2015-lec1-src
 Провести анализ масштабируемости программы (заполнить таблицу)
M = N
Количество потоков
2 4 6 8
T1 T2 S2 T4 S4 T6 S6 T8 S8
20 000
(~ 3 GiB)
40 000
(~ 12 GiB)
Подключение к кластеру oak.cpct.sibsutis.ru
$ ssh mkurnosov@oak.cpct.sibsutis.ru
Password:
[mkurnosov@oak ~]$ mc
Запуск OpenMP-программ на oak.cpct.sibsutis.ru
# Компилируем программу
$ make
gcc -std=c99 -g -Wall -O2 -fopenmp -c matvec.c -o matvec.o
gcc -o matvec matvec.o –fopenmp
# Ставим задание в очередь системы SLURM
$ sbatch ./task-slurm.job
Submitted batch job 3609
# Проверяем состояние очереди задач
$ squeue
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
3609 debug task-slu ivanov R 0:01 1 cn2
# Открываем файл с результатом
$ cat ./slurm-3609.out
Узел кластераСостояниеПользователь
#!/bin/bash
#SBATCH --nodes=1 --ntasks-per-node=8
export OMP_NUM_THREADS=2
./matvec
Спасибо за внимание!
Условная компиляция
#include <stdio.h>
#include <omp.h>
int main(int argc, char **argv)
{
#ifdef _OPENMP
#pragma omp parallel num_threads(6)
{
printf("Hello, multithreaded world: thread %d of %dn",
omp_get_thread_num(), omp_get_num_threads());
}
printf("OpenMP version %dn", _OPENMP);
if (_OPENMP >= 201107)
printf(" OpenMP 3.1 is supportedn");
#endif
return 0;
}
Условная компиляция
$ gcc –fopenmp –o hello ./hello.c
$ ./hello
Hello, multithreaded world: thread 2 of 4
Hello, multithreaded world: thread 1 of 4
Hello, multithreaded world: thread 0 of 4
Hello, multithreaded world: thread 3 of 4
OpenMP version 201107
OpenMP 3.1 is supported
Условная компиляция
$ gcc –o hello ./hello.c
$ ./hello
Время выполнения отдельных потоков
void matrix_vector_product_omp(double *a, double *b, double *c, int m, int n)
{
#pragma omp parallel
{
double t = omp_get_wtime();
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
int items_per_thread = m / nthreads;
int lb = threadid * items_per_thread;
int ub = (threadid == nthreads - 1) ? (m - 1) : (lb + items_per_thread - 1);
for (int i = lb; i <= ub; i++) {
c[i] = 0.0;
for (int j = 0; j < n; j++)
c[i] += a[i * n + j] * b[j];
}
t = omp_get_wtime() - t;
printf("Thread %d items %d [%d - %d], time: %.6fn", threadid, ub - lb + 1, lb, ub, t);
}
}
Многопроцессорные узлы Top500 (2014)
 Среднее количество ядер на сокет (процессор):
9.2 (4, 6, 8, 10, 12, 14, 16)
 Процессоры:
Intel (> 80%), IBM Power, AMD Opteron,
SPARC64, ShenWei, NEC
 Ускорители (12% систем):
Intel Xeon Phi, NVIDIA GPU, ATI/AMD GPU
 Операционная система:
GNU/Linux (96%), IBM AIX (11 шт.), Microsoft (2 шт.)
www.top500.org
Мультиархитектура современных ВС
43
2 nodes Cray XK7
AMD Opteron
Interlagos (16 cores)
SSE/AVXOpenMP, Intel TBB, Cilk,
POSIX Threads
NVIDIA CUDA,
OpenCL, OpenACC
MPI, Cray Chapel, Shmem,
Coarray Fortran, Unified Parallel C
 Уровень одного узла (общая память)
 Многопоточное программирование (intra-node): OpenMP, Intel TBB/Cilk Plus, C11/C++11 Threads
 Программирование ускорителей ( NVIDIA/AMD GPU, Intel Xeon Phi): NVIDA CUDA, OpenCL, OpenACC,
OpenMP 4.0
 Множество вычислительных узлов (распределенная память):
 MPI, Shmem, PGAS (Cray Chapel, IBM X10), Coarray Fortran, Global Arrays, …
 Уровень ядра процессора
 Vectorization (SIMD: SSE/AVX, AltiVec),
cache optimization,
superscalar optimizations

More Related Content

What's hot

Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
Mikhail Kurnosov
 
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Mikhail Kurnosov
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Mikhail Kurnosov
 

What's hot (20)

Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMP
 
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)
 
Семинар 8. Параллельное программирование на MPI (часть 1)
Семинар 8. Параллельное программирование на MPI (часть 1)Семинар 8. Параллельное программирование на MPI (часть 1)
Семинар 8. Параллельное программирование на MPI (часть 1)
 
Семинар 7. Многопоточное программирование на OpenMP (часть 7)
Семинар 7. Многопоточное программирование на OpenMP (часть 7)Семинар 7. Многопоточное программирование на OpenMP (часть 7)
Семинар 7. Многопоточное программирование на OpenMP (часть 7)
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 
Лекция 7. Язык параллельного программирования Intel Cilk Plus
Лекция 7. Язык параллельного программирования Intel Cilk PlusЛекция 7. Язык параллельного программирования Intel Cilk Plus
Лекция 7. Язык параллельного программирования Intel Cilk Plus
 
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
 
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
 
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
 
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
 
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
 
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
 
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисленияПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
 
Лекция 9. Программирование GPU
Лекция 9. Программирование GPUЛекция 9. Программирование GPU
Лекция 9. Программирование GPU
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
 

Viewers also liked

Язык параллельного программирования Intel Cilk Plus
Язык параллельного программирования Intel Cilk PlusЯзык параллельного программирования Intel Cilk Plus
Язык параллельного программирования Intel Cilk Plus
Mikhail Kurnosov
 

Viewers also liked (12)

Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
 
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
 
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Векторизация кода (семинар 3)
Векторизация кода (семинар 3)
 
Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)
 
Язык параллельного программирования Intel Cilk Plus
Язык параллельного программирования Intel Cilk PlusЯзык параллельного программирования Intel Cilk Plus
Язык параллельного программирования Intel Cilk Plus
 
What Makes Great Infographics
What Makes Great InfographicsWhat Makes Great Infographics
What Makes Great Infographics
 
Masters of SlideShare
Masters of SlideShareMasters of SlideShare
Masters of SlideShare
 
STOP! VIEW THIS! 10-Step Checklist When Uploading to Slideshare
STOP! VIEW THIS! 10-Step Checklist When Uploading to SlideshareSTOP! VIEW THIS! 10-Step Checklist When Uploading to Slideshare
STOP! VIEW THIS! 10-Step Checklist When Uploading to Slideshare
 
You Suck At PowerPoint!
You Suck At PowerPoint!You Suck At PowerPoint!
You Suck At PowerPoint!
 
10 Ways to Win at SlideShare SEO & Presentation Optimization
10 Ways to Win at SlideShare SEO & Presentation Optimization10 Ways to Win at SlideShare SEO & Presentation Optimization
10 Ways to Win at SlideShare SEO & Presentation Optimization
 
How To Get More From SlideShare - Super-Simple Tips For Content Marketing
How To Get More From SlideShare - Super-Simple Tips For Content MarketingHow To Get More From SlideShare - Super-Simple Tips For Content Marketing
How To Get More From SlideShare - Super-Simple Tips For Content Marketing
 
How to Make Awesome SlideShares: Tips & Tricks
How to Make Awesome SlideShares: Tips & TricksHow to Make Awesome SlideShares: Tips & Tricks
How to Make Awesome SlideShares: Tips & Tricks
 

Similar to Семинар 1. Многопоточное программирование на OpenMP (часть 1)

Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12
Alex Tutubalin
 
C++ весна 2014 лекция 2
C++ весна 2014 лекция 2C++ весна 2014 лекция 2
C++ весна 2014 лекция 2
Technopark
 
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Mikhail Kurnosov
 
Эффективное использование x86-совместимых CPU (Алексей Тутубалин)
Эффективное использование x86-совместимых CPU (Алексей Тутубалин)Эффективное использование x86-совместимых CPU (Алексей Тутубалин)
Эффективное использование x86-совместимых CPU (Алексей Тутубалин)
Ontico
 
Лекция 11: Программирование графических процессоров на NVIDIA CUDA
Лекция 11: Программирование графических процессоров на NVIDIA CUDAЛекция 11: Программирование графических процессоров на NVIDIA CUDA
Лекция 11: Программирование графических процессоров на NVIDIA CUDA
Mikhail Kurnosov
 
Доклад на Highload-2012
Доклад на Highload-2012Доклад на Highload-2012
Доклад на Highload-2012
Alex Tutubalin
 
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Mikhail Kurnosov
 
Лекция 3: Векторизация кода (Code vectorization, SIMD, SSE, AVX)
Лекция 3: Векторизация кода (Code vectorization, SIMD, SSE, AVX)Лекция 3: Векторизация кода (Code vectorization, SIMD, SSE, AVX)
Лекция 3: Векторизация кода (Code vectorization, SIMD, SSE, AVX)
Mikhail Kurnosov
 
Операционные системы
Операционные системыОперационные системы
Операционные системы
yaevents
 

Similar to Семинар 1. Многопоточное программирование на OpenMP (часть 1) (20)

Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12
 
CUDA Course 2010 at MSU
CUDA Course 2010 at MSUCUDA Course 2010 at MSU
CUDA Course 2010 at MSU
 
C++ весна 2014 лекция 2
C++ весна 2014 лекция 2C++ весна 2014 лекция 2
C++ весна 2014 лекция 2
 
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
 
TMPA-2013 Sartakov: Genode
TMPA-2013 Sartakov: GenodeTMPA-2013 Sartakov: Genode
TMPA-2013 Sartakov: Genode
 
введение в Gpu
введение в Gpuвведение в Gpu
введение в Gpu
 
Вебинар: Основы распараллеливания С++ программ при помощи OpenMP
Вебинар: Основы распараллеливания С++ программ при помощи OpenMPВебинар: Основы распараллеливания С++ программ при помощи OpenMP
Вебинар: Основы распараллеливания С++ программ при помощи OpenMP
 
Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...
 
Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...
 
Эффективное использование x86-совместимых CPU (Алексей Тутубалин)
Эффективное использование x86-совместимых CPU (Алексей Тутубалин)Эффективное использование x86-совместимых CPU (Алексей Тутубалин)
Эффективное использование x86-совместимых CPU (Алексей Тутубалин)
 
кластеры и суперкомпьютеры
кластеры и суперкомпьютерыкластеры и суперкомпьютеры
кластеры и суперкомпьютеры
 
11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)
 
Параллельное программирование на современных видеокартах
Параллельное программирование на современных видеокартахПараллельное программирование на современных видеокартах
Параллельное программирование на современных видеокартах
 
Лекция 11: Программирование графических процессоров на NVIDIA CUDA
Лекция 11: Программирование графических процессоров на NVIDIA CUDAЛекция 11: Программирование графических процессоров на NVIDIA CUDA
Лекция 11: Программирование графических процессоров на NVIDIA CUDA
 
Доклад на Highload-2012
Доклад на Highload-2012Доклад на Highload-2012
Доклад на Highload-2012
 
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
 
Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...
 
Лекция 3: Векторизация кода (Code vectorization, SIMD, SSE, AVX)
Лекция 3: Векторизация кода (Code vectorization, SIMD, SSE, AVX)Лекция 3: Векторизация кода (Code vectorization, SIMD, SSE, AVX)
Лекция 3: Векторизация кода (Code vectorization, SIMD, SSE, AVX)
 
Операционные системы
Операционные системыОперационные системы
Операционные системы
 
Efficiency vvv
Efficiency vvvEfficiency vvv
Efficiency vvv
 

More from Mikhail Kurnosov

More from Mikhail Kurnosov (12)

Лекция 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. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)
 
Лекция 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. Графы. Обходы графов
Лекция 8. Графы. Обходы графовЛекция 8. Графы. Обходы графов
Лекция 8. Графы. Обходы графов
 
Лекция 7. Бинарные кучи. Пирамидальная сортировка
Лекция 7. Бинарные кучи. Пирамидальная сортировкаЛекция 7. Бинарные кучи. Пирамидальная сортировка
Лекция 7. Бинарные кучи. Пирамидальная сортировка
 
Лекция 6. Хеш-таблицы
Лекция 6. Хеш-таблицыЛекция 6. Хеш-таблицы
Лекция 6. Хеш-таблицы
 

Семинар 1. Многопоточное программирование на OpenMP (часть 1)

  • 1. Семинар 1 Стандарт OpenMP (часть 1) Михаил Курносов E-mail: mkurnosov@gmail.com WWW: www.mkurnosov.net Цикл семинаров «Основы параллельного программирования» Институт физики полупроводников им. А. В. Ржанова СО РАН Новосибирск, 2015 CC-BY
  • 2. Многопроцессорные системы с общей памятью  Процессоры SMP-системы имеют одинаковое время доступа к разделяемой памяти: симметричный, однородный доступ к памяти – Uniform Memory Access (UMA)  Системная шина (system bus, crossbar) – узкое место, ограничивающее производительность вычислительного узла (процессоры конкурируют за доступ к ней)  Проблемы: низкая масштабируемость, обеспечение когерентности (согласованности) кеш-памяти процессоров и разделяемой памяти CPU 1 Cache CPU 2 Cache CPU N Cache I/O Bus arbiter System bus Shared memory (RAM) SMP-системы
  • 3. Многопроцессорные системы с общей памятью  NUMA (Non-Uniform Memory Architecture) – многопроцессорная вычислительная система с неоднородным доступом к разделяемой памяти  Процессоры сгруппированы в NUMA-узлы со своей локальной памятью (NUMA nodes)  Разное время доступа к локальной памяти NUMA-узла (NUMA-node) и памяти другого узла  Большая масштабируемость по сравнению с SMP-системами  Проблемы: обеспечение когерентности кеш-памяти процессоров NUMA-системы Local access (fast) Remote access (slow)
  • 4. Поток 0 Процессы и потоки int fun() { // … } Стек потока 0 Куча (heap) (динамически выделяемая память: malloc/free) Область неинициализированных данных (BSS) (глобальные неинициализированные переменные) Область инициализированных данных (Data) (глобальные инициализированные переменные) // Uninitialized data (BSS) int sum[100]; // BSS // Initialized data (Data) float grid[100][100] = {1.0}; int main() { // Local variable (stack) double s = 0.0; // Allocate from the heap float *x = malloc(1000); // ... free(x); }
  • 5. Поток 0 Процессы и потоки int fun() { // … } Поток 1 int fun() { // … } Поток N-1 int fun() { // … } … Стек потока 0 Стек потока 1 Стек потока N - 1 … Куча (heap) (динамически выделяемая память: malloc/free) Область неинициализированных данных (BSS) (глобальные неинициализированные переменные) Область инициализированных данных (Data) (глобальные инициализированные переменные) // Uninitialized data (BSS) int sum[100]; // BSS // Initialized data (Data) float grid[100][100] = {1.0}; int main() { // Local variable (stack) double s = 0.0; // Allocate from the heap float *x = malloc(1000); // ... free(x); }
  • 6. Средства многопоточного программирования Hardware (Multi-core processor, SMP/NUMA) Kernel thread Process scheduler Системные вызовы (System calls) POSIX Threads Apple OS X Cocoa, Pthreads Уровень ядра (Kernel space) Операционная система 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 Cilk Plus  С++11 Threads  C11 Threads  C# Threads  Java Threads  Erlang Threads  Haskell Threads OpenMP pthreads (glibc) clone() (Linux syscall)
  • 7. Стандарт OpenMP  OpenMP (Open Multi-Processing) – стандарт, определяющий набор директив компилятора, библиотечных процедур и переменных среды окружения для создания многопоточных программ  Разрабатывается в рамках OpenMP Architecture Review Board с 1997 года  OpenMP 2.5 (2005), OpenMP 3.0 (2008), OpenMP 3.1 (2011), OpenMP 4.0 (2013)  http://www.openmp.org  http://www.openmp.org/mp-documents/OpenMP4.0.0.pdf  Требуется поддержка со стороны компилятора
  • 8. Поддержка компиляторами Compiler Information GNU GCC Option: –fopenmp gcc 4.2 – OpenMP 2.5, gcc 4.4 – OpenMP 3.0, gcc 4.7 – OpenMP 3.1 gcc 4.9 – OpenMP 4.0 Clang (LLVM) OpenMP 3.1 сlang + Intel OpenMP RTL http://clang-omp.github.io/ Intel C/C++, Fortran OpenMP 4.0 Option: –Qopenmp, –openmp Oracle Solaris Studio C/C++/Fortran OpenMP 4.0 Option: –xopenmp Microsoft Visual Studio C++ Option: /openmp OpenMP 2.0 only Other compilers: IBM XL, PathScale, PGI, Absoft Pro, …
  • 9. 0 1 0 0 1 2 0 Модель выполнения OpenMP-программы  Динамическое управление потоками в модели Fork-Join:  Fork – порождение нового потока  Join – ожидание завершения потока (объединение потоков управления)  OpenMP-программа – совокупность последовательных участков кода (serial code) и параллельных регионов (parallel region)  Каждый поток имеет логический номер: 0, 1, 2, …  Главный поток (master) имеет номер 0  Параллельные регионы могут быть вложенными Parallel region Parallel region Barrier Barrier
  • 10. Hello, World #include <stdio.h> #include <omp.h> int main(int argc, char **argv) { #pragma omp parallel /* <-- Fork */ { printf("Hello, multithreaded world: thread %d of %dn", omp_get_thread_num(), omp_get_num_threads()); } /* <-- Barrier & join */ return 0; }
  • 11. Компиляция и запуск OpenMP-программы $ gcc –fopenmp –o hello ./hello.c $ ./hello Hello, multithreaded world: thread 0 of 4 Hello, multithreaded world: thread 1 of 4 Hello, multithreaded world: thread 3 of 4 Hello, multithreaded world: thread 2 of 4  По умолчанию количество потоков в параллельном регионе равно числу логических процессоров в системе  Порядок выполнения потоков заранее неизвестен – определяется планировщиком операционной системы
  • 12. Указание числа потоков в параллельных регионах $ export OMP_NUM_THREADS=8 $ ./hello Hello, multithreaded world: thread 1 of 8 Hello, multithreaded world: thread 2 of 8 Hello, multithreaded world: thread 3 of 8 Hello, multithreaded world: thread 0 of 8 Hello, multithreaded world: thread 4 of 8 Hello, multithreaded world: thread 5 of 8 Hello, multithreaded world: thread 6 of 8 Hello, multithreaded world: thread 7 of 8
  • 13. Задание числа потоков в параллельном регионе #include <stdio.h> #include <omp.h> int main(int argc, char **argv) { #pragma omp parallel num_threads(6) { printf("Hello, multithreaded world: thread %d of %dn", omp_get_thread_num(), omp_get_num_threads()); } return 0; }
  • 14. Задание числа потоков в параллельном регионе $ export OMP_NUM_THREADS=8 $ ./hello Hello, multithreaded world: thread 2 of 6 Hello, multithreaded world: thread 3 of 6 Hello, multithreaded world: thread 1 of 6 Hello, multithreaded world: thread 0 of 6 Hello, multithreaded world: thread 4 of 6 Hello, multithreaded world: thread 5 of 6  Директива num_threads имеет приоритет над значением переменной среды окружения OMP_NUM_THREADS
  • 15. Список потоков процесса #include <stdio.h> #include <omp.h> #include <time.h> int main(int argc, char **argv) { #pragma omp parallel num_threads(6) { printf("Hello, multithreaded world: thread %d of %dn", omp_get_thread_num(), omp_get_num_threads()); /* Sleep for 30 seconds */ nanosleep(&(struct timespec){.tv_sec = 30}, NULL); } return 0; }
  • 16. Список потоков процесса $ ./hello & $ ps -eLo pid,tid,psr,args | grep hello 6157 6157 0 ./hello 6157 6158 1 ./hello 6157 6159 0 ./hello 6157 6160 1 ./hello 6157 6161 0 ./hello 6157 6162 1 ./hello 6165 6165 2 grep hello  Номер процесса (PID)  Номер потока (TID)  Логический процессор (PSR)  Название исполняемого файла  Информация о логических процессорах системы:  /proc/cpuinfo  /sys/devices/system/cpu
  • 17. Умножение матрицы на вектор (DGEMV) 𝐴 = 𝑎11 𝑎12 … 𝑎1𝑛 𝑎21 𝑎22 … 𝑎2𝑛 … … … … 𝑎 𝑚1 𝑎 𝑚2 … 𝑎 𝑚𝑛 𝐵 = 𝑏1 𝑏2 … 𝑏 𝑛 𝑐𝑖 = 𝑗=1 𝑛 𝑎𝑖𝑗 ∙ 𝑏𝑗 , 𝑖 = 1,2, … , 𝑚. 𝑪 𝒎×𝟏 = 𝑨 𝒎×𝒏 ∙ 𝑩 𝒏×𝟏  Требуется вычислить произведение прямоугольной матрицы A размера 𝑚 × 𝑛 на вектор-столбец B размера 𝑚 × 1 (BLAS Level 2, DGEMV) 𝐶 = 𝑐1 𝑐2 … 𝑐 𝑚
  • 18. DGEMV: последовательная версия /* * matrix_vector_product: Compute matrix-vector product c[m] = a[m][n] * b[n] */ void matrix_vector_product(double *a, double *b, double *c, int m, int n) { for (int i = 0; i < m; i++) { c[i] = 0.0; for (int j = 0; j < n; j++) c[i] += a[i * n + j] * b[j]; } } 𝑐𝑖 = 𝑗=1 𝑛 𝑎𝑖𝑗 ∙ 𝑏𝑗 , 𝑖 = 1,2, … , 𝑚.
  • 19. DGEMV: последовательная версия void run_serial() { double *a, *b, *c; a = xmalloc(sizeof(*a) * m * n); b = xmalloc(sizeof(*b) * n); c = xmalloc(sizeof(*c) * m); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) a[i * n + j] = i + j; } for (int j = 0; j < n; j++) b[j] = j; double t = wtime(); matrix_vector_product(a, b, c, m, n); t = wtime() - t; printf("Elapsed time (serial): %.6f sec.n", t); free(a); free(b); free(c); }
  • 20. DGEMV: параллельная версия A[m][n] C[m] B[n] for (int i = 0; i < m; i++) { c[i] = 0.0; for (int j = 0; j < n; j++) c[i] += a[i * n + j] * b[j]; } Требования к параллельному алгоритму  Максимальная загрузка потоков вычислениями  Минимум совместно используемых ячеек памяти – независимые области данных
  • 21. DGEMV: параллельная версия A[m][n] C[m] B[n] Распараллеливание внешнего цикла  Каждом потоку выделяется часть строк матрицы A Поток 1 Поток 2 Поток 3 for (int i = 0; i < m; i++) { c[i] = 0.0; for (int j = 0; j < n; j++) c[i] += a[i * n + j] * b[j]; } Поток 4
  • 22. DGEMV: параллельная версия /* matrix_vector_product_omp: Compute matrix-vector product c[m] = a[m][n] * b[n] */ void matrix_vector_product_omp(double *a, double *b, double *c, int m, int n) { #pragma omp parallel { int nthreads = omp_get_num_threads(); int threadid = omp_get_thread_num(); int items_per_thread = m / nthreads; int lb = threadid * items_per_thread; int ub = (threadid == nthreads - 1) ? (m - 1) : (lb + items_per_thread - 1); for (int i = lb; i <= ub; i++) { c[i] = 0.0; for (int j = 0; j < n; j++) c[i] += a[i * n + j] * b[j]; } } } A[m][n] C[m] lb ub
  • 23. DGEMV: параллельная версия void run_parallel() { double *a, *b, *c; // Allocate memory for 2-d array a[m, n] a = xmalloc(sizeof(*a) * m * n); b = xmalloc(sizeof(*b) * n); c = xmalloc(sizeof(*c) * m); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) a[i * n + j] = i + j; } for (int j = 0; j < n; j++) b[j] = j; double t = wtime(); matrix_vector_product_omp(a, b, c, m, n); t = wtime() - t; printf("Elapsed time (parallel): %.6f sec.n", t); free(a); free(b); free(c); }
  • 24. DGEMV: параллельная версия int main(int argc, char **argv) { printf("Matrix-vector product (c[m] = a[m, n] * b[n]; m = %d, n = %d)n", m, n); printf("Memory used: %" PRIu64 " MiBn", ((m * n + m + n) * sizeof(double)) >> 20); run_serial(); run_parallel(); return 0; }
  • 25. Анализ эффективности OpenMP-версии  Введем обозначения:  𝑻(𝒏) – время выполнения последовательной программы (serial program) при заданном размере n входных данных  𝑻 𝒑(𝒏, 𝒑) – время выполнения параллельной программы (parallel program) на p процессорах при заданном размере n входных данных  Коэффициент Sp(n) ускорения параллельной программ (Speedup): 𝑺 𝒑 𝒏 = 𝑻(𝒏) 𝑻 𝒑(𝒏)  Как правило 𝑆 𝑝 𝑛 ≤ 𝑝  Цель распараллеливания – достичь линейного ускорения на наибольшем числе процессоров: 𝑆 𝑝 𝑛 ≥ 𝑐 ∙ 𝑝, при 𝑝 → ∞ и 𝑐 > 0 Во сколько раз параллельная программа выполняется на p процессорах быстрее последовательной программы при обработке одних и тех же данных размера n
  • 26. Анализ эффективности OpenMP-версии M = N Количество потоков 2 4 6 8 T1 T2 S2 T4 S4 T6 S6 T8 S8 20 000 (~ 3 GiB) 0.73 0.34 2.12 0.24 3.11 0.23 3.14 0.25 2.84 40 000 (~ 12 GiB) 2.98 1.30 2.29 0.95 3.11 0.91 3.21 0.87 3.38 49 000 (~ 18 GiB) 1.23 3.69 0 1 2 3 4 5 6 7 8 9 2 4 6 8 Sp p Linear M = 20 000 M = 40 000 Вычислительный узел кластера Oak (oak.cpct.sibsutis.ru):  System board: Intel 5520UR  8 ядер – два Intel Quad Xeon E5620 (2.4 GHz)  24 GiB RAM – 6 x 4GB DDR3 1067 MHz  CentOS 6.5 x86_64, GCC 4.4.7  Ключи компиляции: -std=c99 -Wall -O2 -fopenmp Низкая масштабируемость! Причины ?
  • 27. DGEMV: конкуренция за доступ к памяти /* matrix_vector_product_omp: Compute matrix-vector product c[m] = a[m][n] * b[n] */ void matrix_vector_product_omp(double *a, double *b, double *c, int m, int n) { #pragma omp parallel { int nthreads = omp_get_num_threads(); int threadid = omp_get_thread_num(); int items_per_thread = m / nthreads; int lb = threadid * items_per_thread; int ub = (threadid == nthreads - 1) ? (m - 1) : (lb + items_per_thread - 1); for (int i = lb; i <= ub; i++) { c[i] = 0.0; // Store – запись в память for (int j = 0; j < n; j++) // Memory ops: Load c[i], Load a[i][j], Load b[j], Store c[i] c[i] += a[i * n + j] * b[j]; } } }  DGEMV – data intensive application  Конкуренция за доступ к контролеру памяти  ALU ядер загружены незначительно
  • 28. Конфигурация узла кластера Oak Вычислительный узел кластера Oak (oak.cpct.sibsutis.ru):  System board: Intel 5520UR (NUMA-система)  Процессоры связаны шиной QPI Link: 5.86 GT/s  24 GiB RAM – 6 x 4GB DDR3 1067 MHz $ numactl --hardware available: 2 nodes (0-1) node 0 cpus: 0 2 4 6 node 0 size: 12224 MB node 0 free: 11443 MB node 1 cpus: 1 3 5 7 node 1 size: 12288 MB node 1 free: 11837 MB node distances: node 0 1 0: 10 21 1: 21 10 http://download.intel.com/support/motherboards/server/s5520ur/sb/e44031012_s5520ur_s5520urt_tps_r1_9.pdf CPU0 CPU1 DRAMDRAM QPI QPI QPI NUMA-node 0 NUMA-node 1
  • 29. Конфигурация узла кластера Oak Вычислительный узел кластера Oak (oak.cpct.sibsutis.ru):  System board: Intel 5520UR (NUMA-система)  Процессоры связаны шиной QPI Link: 5.86 GT/s  24 GiB RAM – 6 x 4GB DDR3 1067 MHz $ numactl --hardware available: 2 nodes (0-1) node 0 cpus: 0 2 4 6 node 0 size: 12224 MB node 0 free: 11443 MB node 1 cpus: 1 3 5 7 node 1 size: 12288 MB node 1 free: 11837 MB node distances: node 0 1 0: 10 21 1: 21 10 http://download.intel.com/support/motherboards/server/s5520ur/sb/e44031012_s5520ur_s5520urt_tps_r1_9.pdf CPU0 CPU1 DRAMDRAM QPI QPI QPI NUMA-node 0 NUMA-node 1 А на каком NUMA-узле (узлах) размещена матрица A и векторы B, С?
  • 30. Выделение памяти потокам в GNU/Linux  Страница памяти выделяется с NUMA-узла того потока, который первый к ней обратился (first-touch policy)  Данные желательно инициализировать теми потоками, которые будут с ними работать void run_parallel() { double *a, *b, *c; // Allocate memory for 2-d array a[m, n] a = xmalloc(sizeof(*a) * m * n); b = xmalloc(sizeof(*b) * n); c = xmalloc(sizeof(*c) * m); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) a[i * n + j] = i + j; } for (int j = 0; j < n; j++) b[j] = j; С1 С2 С3 С4 RAM (12 GiB) NUMA-node 0 С1 С2 С3 С4 RAM (12 GiB) NUMA-node 1 Bus Thread 0  Поток 0 запрашивает выделение памяти под массивы  Пока хватает памяти, ядро выделяет страницы с NUMA-узла 0, затем с NUMA-узла 1 a[][] b c
  • 31. Выделение памяти потокам в GNU/Linux  Страница памяти выделяется с NUMA-узла того потока, который первый к ней обратился (first-touch policy)  Данные желательно инициализировать теми потоками, которые будут с ними работать void run_parallel() { double *a, *b, *c; // Allocate memory for 2-d array a[m, n] a = xmalloc(sizeof(*a) * m * n); b = xmalloc(sizeof(*b) * n); c = xmalloc(sizeof(*c) * m); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) a[i * n + j] = i + j; } for (int j = 0; j < n; j++) b[j] = j; С1 С2 С3 С4 RAM (12 GiB) NUMA-node 0 С1 С2 С3 С4 RAM (12 GiB) NUMA-node 1 Bus Thread 0  Обращение к массивам из потоков NUMA-узла 1 будет идти через межпроцессорную шину в память узла 0 a[][] b c Thread 2Thread 1 Thread 3
  • 32. Параллельная инициализация массивов void run_parallel() { double *a, *b, *c; // Allocate memory for 2-d array a[m, n] a = xmalloc(sizeof(*a) * m * n); b = xmalloc(sizeof(*b) * n); c = xmalloc(sizeof(*c) * m); #pragma omp parallel { int nthreads = omp_get_num_threads(); int threadid = omp_get_thread_num(); int items_per_thread = m / nthreads; int lb = threadid * items_per_thread; int ub = (threadid == nthreads - 1) ? (m - 1) : (lb + items_per_thread - 1); for (int i = lb; i <= ub; i++) { for (int j = 0; j < n; j++) a[i * n + j] = i + j; c[i] = 0.0; } } for (int j = 0; j < n; j++) b[j] = j; /* ... */ }
  • 33. Анализ эффективности OpenMP-версии (2) M = N Количество потоков 2 4 6 8 T1 T2 S2 T4 S4 T6 S6 T8 S8 20 000 (~ 3 GiB) 0.73 0.34 2.12 0.24 3.11 0.23 3.14 0.25 2.84 40 000 (~ 12 GiB) 2.98 1.30 2.29 0.95 3.11 0.91 3.21 0.87 3.38 49 000 (~ 18 GiB) 1.23 3.69 Parallel initialization 40 000 (~ 12 GiB) 2.98 1.22 2.43 0.67 4.41 0.65 4.65 0.54 5.48 49 000 (~ 18 GiB) 0.83 5.41 0 1 2 3 4 5 6 7 8 9 2 4 6 8 Sp p Linear M = 20 000 M = 40 000 Sp p Linear M = 20 000 M = 40 000 Par. init Суперлинейное ускорение (super-linear speedup): 𝑆 𝑝 𝑛 > 𝑝 Улучшили масштабируемость Дальнейшие оптимизации:  Эффективный доступ к кеш-памяти  Векторизация кода (SSE/AVX)  …
  • 34. Задание  Реализовать многопоточную версию программы умножения матрицы на вектор с параллельной инициализацией массивов  Шаблон программы для выполнения задания находится в каталоге task  На кластере oak примеры находятся в папке /home/pub/parprog2015-lec1-src  Провести анализ масштабируемости программы (заполнить таблицу) M = N Количество потоков 2 4 6 8 T1 T2 S2 T4 S4 T6 S6 T8 S8 20 000 (~ 3 GiB) 40 000 (~ 12 GiB)
  • 35. Подключение к кластеру oak.cpct.sibsutis.ru $ ssh mkurnosov@oak.cpct.sibsutis.ru Password: [mkurnosov@oak ~]$ mc
  • 36. Запуск OpenMP-программ на oak.cpct.sibsutis.ru # Компилируем программу $ make gcc -std=c99 -g -Wall -O2 -fopenmp -c matvec.c -o matvec.o gcc -o matvec matvec.o –fopenmp # Ставим задание в очередь системы SLURM $ sbatch ./task-slurm.job Submitted batch job 3609 # Проверяем состояние очереди задач $ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 3609 debug task-slu ivanov R 0:01 1 cn2 # Открываем файл с результатом $ cat ./slurm-3609.out Узел кластераСостояниеПользователь #!/bin/bash #SBATCH --nodes=1 --ntasks-per-node=8 export OMP_NUM_THREADS=2 ./matvec
  • 38. Условная компиляция #include <stdio.h> #include <omp.h> int main(int argc, char **argv) { #ifdef _OPENMP #pragma omp parallel num_threads(6) { printf("Hello, multithreaded world: thread %d of %dn", omp_get_thread_num(), omp_get_num_threads()); } printf("OpenMP version %dn", _OPENMP); if (_OPENMP >= 201107) printf(" OpenMP 3.1 is supportedn"); #endif return 0; }
  • 39. Условная компиляция $ gcc –fopenmp –o hello ./hello.c $ ./hello Hello, multithreaded world: thread 2 of 4 Hello, multithreaded world: thread 1 of 4 Hello, multithreaded world: thread 0 of 4 Hello, multithreaded world: thread 3 of 4 OpenMP version 201107 OpenMP 3.1 is supported
  • 40. Условная компиляция $ gcc –o hello ./hello.c $ ./hello
  • 41. Время выполнения отдельных потоков void matrix_vector_product_omp(double *a, double *b, double *c, int m, int n) { #pragma omp parallel { double t = omp_get_wtime(); int nthreads = omp_get_num_threads(); int threadid = omp_get_thread_num(); int items_per_thread = m / nthreads; int lb = threadid * items_per_thread; int ub = (threadid == nthreads - 1) ? (m - 1) : (lb + items_per_thread - 1); for (int i = lb; i <= ub; i++) { c[i] = 0.0; for (int j = 0; j < n; j++) c[i] += a[i * n + j] * b[j]; } t = omp_get_wtime() - t; printf("Thread %d items %d [%d - %d], time: %.6fn", threadid, ub - lb + 1, lb, ub, t); } }
  • 42. Многопроцессорные узлы Top500 (2014)  Среднее количество ядер на сокет (процессор): 9.2 (4, 6, 8, 10, 12, 14, 16)  Процессоры: Intel (> 80%), IBM Power, AMD Opteron, SPARC64, ShenWei, NEC  Ускорители (12% систем): Intel Xeon Phi, NVIDIA GPU, ATI/AMD GPU  Операционная система: GNU/Linux (96%), IBM AIX (11 шт.), Microsoft (2 шт.) www.top500.org
  • 43. Мультиархитектура современных ВС 43 2 nodes Cray XK7 AMD Opteron Interlagos (16 cores) SSE/AVXOpenMP, Intel TBB, Cilk, POSIX Threads NVIDIA CUDA, OpenCL, OpenACC MPI, Cray Chapel, Shmem, Coarray Fortran, Unified Parallel C  Уровень одного узла (общая память)  Многопоточное программирование (intra-node): OpenMP, Intel TBB/Cilk Plus, C11/C++11 Threads  Программирование ускорителей ( NVIDIA/AMD GPU, Intel Xeon Phi): NVIDA CUDA, OpenCL, OpenACC, OpenMP 4.0  Множество вычислительных узлов (распределенная память):  MPI, Shmem, PGAS (Cray Chapel, IBM X10), Coarray Fortran, Global Arrays, …  Уровень ядра процессора  Vectorization (SIMD: SSE/AVX, AltiVec), cache optimization, superscalar optimizations