SlideShare ist ein Scribd-Unternehmen logo
1 von 17
Downloaden Sie, um offline zu lesen
Семинар 2
Стандарт OpenMP (часть 2)
Михаил Курносов
E-mail: mkurnosov@gmail.com
WWW: www.mkurnosov.net
Цикл семинаров «Основы параллельного программирования»
Институт физики полупроводников им. А. В. Ржанова СО РАН
Новосибирск, 2015 CC-BY
Численное интегрирование (метод прямоугольников)
f(x)
x
x0
ba
x1
x2
x3
xn − 1
Формула средних прямоугольников const double a = -4.0; /* [a, b] */
const double b = 4.0;
const int nsteps = 40000000; /* n */
double func(double x)
{
return exp(-x * x);
}
double integrate(double a, double b, int n)
{
double h = (b - a) / n;
double sum = 0.0;
for (int i = 0; i < n; i++)
sum += func(a + h * (i + 0.5));
sum *= h;
return sum;
}
Распараллеливание
const double a = -4.0;
const double b = 4.0;
const int nsteps = 40000000;
double func(double x)
{
return exp(-x * x);
}
double integrate(double a, double b, int n)
{
double h = (b - a) / n;
double sum = 0.0;
for (int i = 0; i < n; i++)
sum += func(a + h * (i + 0.5));
sum *= h;
return sum;
}
 Итерации цикла for распределим между потоками
 Каждый поток вычисляет часть суммы (площади)
 Варианты распределения итераций (точек)
между p потоками:
T0 T0 T0 T0 T1 T1 T1 T1 T2 T2 T2 T2
Thread 0 Thread 1 Thread 2
T0 T1 T2 T0 T1 T2 T0 T1 T2 T0 T1 T2
Thread 0, Thread1, Thread 2, Thread 0, Thread 1, Thread 2, ...
1) Разбиение на p смежных непрерывных частей
2) Циклическое распределение итераций по потокам
Параллельная версия
double integrate_omp(double (*func)(double), double a, double b, int n)
{
double h = (b - a) / n;
double sum = 0.0;
#pragma omp parallel
{
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
int items_per_thread = n / nthreads;
int lb = threadid * items_per_thread;
int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1);
for (int i = lb; i <= ub; i++)
sum += func(a + h * (i + 0.5));
}
sum *= h;
return sum;
}
T0 T0 T0 T0 T1 T1 T1 T1 T2 T2 T2 T2
Thread 0 Thread 1 Thread 2
Разбиение пространства итераций
на смежные непрерывные части
lb ub
Параллельная версия (продолжение)
const double PI = 3.14159265358979323846;
const double a = -4.0;
const double b = 4.0;
const int nsteps = 40000000;
double run_serial()
{
double t = wtime();
double res = integrate(func, a, b, nsteps);
t = wtime() - t;
printf("Result (serial): %.12f; error %.12fn", res, fabs(res - sqrt(PI)));
return t;
}
double run_parallel()
{
double t = wtime();
double res = integrate_omp(func, a, b, nsteps);
t = wtime() - t;
printf("Result (parallel): %.12f; error %.12fn", res, fabs(res - sqrt(PI)));
return t;
}
int main(int argc, char **argv)
{
printf("Integration f(x) on [%.12f, %.12f], nsteps = %dn", a, b, nsteps);
double tserial = run_serial();
double tparallel = run_parallel();
printf("Execution time (serial): %.6fn", tserial);
printf("Execution time (parallel): %.6fn", tparallel);
printf("Speedup: %.2fn", tserial / tparallel);
return 0;
}
Компиляция и запуск
$ make
gcc -std=c99 -Wall -O2 -fopenmp -c integrate.c -o integrate.o
gcc -o integrate integrate.o -lm -fopenmp
$ export OMP_NUM_THREADS=4
$ ./integrate
Result (serial): 1.772453823579; error 0.000000027326
Result (parallel): 0.896639185158; error 0.875814665748
$ ./integrate
Result (serial): 1.772453823579; error 0.000000027326
Result (parallel): 0.794717040479; error 0.977736810426
$ ./integrate
Result (serial): 1.772453823579; error 0.000000027326
Result (parallel): 0.771561715425; error 1.000892135481
На каждом запуске
разные результаты!
В чем причина?
Состояние гонки данных (race condition, data race)
double integrate_omp(double (*func)(double), double a, double b, int n)
{
double h = (b - a) / n;
double sum = 0.0;
#pragma omp parallel
{
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
int items_per_thread = n / nthreads;
int lb = threadid * items_per_thread;
int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1);
for (int i = lb; i <= ub; i++)
sum += func(a + h * (i + 0.5));
}
sum *= h;
return sum;
}
Ошибка - race condition
 Несколько потоков одновременно
читают и записывают переменную sum
 Значение sum зависит от порядка
выполнения потоков
Состояние гонки данных (race condition, data race)
Два потока одновременно увеличивают значение переменной x на 1
(начальное значение x = 0)
Thread 0
x = x + 1;
Thread 1
x = x + 1;
Ожидаемый (идеальный) порядок выполнения потоков: первый поток увеличил x, затем второй
Time Thread 0 Thread 1 x
0
Значение x = 0 загружается
в регистр R процессора
0
1
Значение 0 в регистре R
увеличивается на 1
0
2
Значение 1 из регистра R
записывается в x
1
3
Значение x = 1 загружается
в регистр R процессора
1
4
Значение 1 в регистре R
увеличивается на 1
1
5
Значение 2 из регистра R
записывается в x 2 Ошибки нет
Состояние гонки данных (race condition, data race)
Два потока одновременно увеличивают значение переменной x на 1
(начальное значение x = 0)
Thread 0
x = x + 1;
Thread 1
x = x + 1;
Реальный порядок выполнения потоков (недетерминированный)
(потоки могут выполняться в любой последовательности,
приостанавливаться и запускаться)
Time Thread 0 Thread 1 x
0
Значение x = 0 загружается
в регистр R процессора
0
1
Значение 0 в регистре R
увеличивается на 1
Значение x = 0 загружается
в регистр R процессора
0
2
Значение 1 из регистра R
записывается в x
Значение 1 в регистре R
увеличивается на 1
1
3
Значение 1 из регистра R
записывается в x 1
Ошибка - data race
(ожидали 2)
Устранение гонки данных
double integrate_omp(double (*func)(double), double a, double b, int n)
{
double h = (b - a) / n;
double sum = 0.0;
#pragma omp parallel
{
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
int items_per_thread = n / nthreads;
int lb = threadid * items_per_thread;
int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1);
for (int i = lb; i <= ub; i++)
sum += func(a + h * (i + 0.5));
}
sum *= h;
return sum;
}
Надо сделать так,
чтобы увеличение переменной sum
в любой момент времени
выполнялось только одним потоком
Критическая секция (critical section)
double integrate_omp(double (*func)(double), double a, double b, int n)
{
double h = (b - a) / n;
double sum = 0.0;
#pragma omp parallel
{
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
int items_per_thread = n / nthreads;
int lb = threadid * items_per_thread;
int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1);
for (int i = lb; i <= ub; i++) {
double f = func(a + h * (i + 0.5));
#pragma omp critical
{
sum += f;
}
}
}
sum *= h;
return sum;
}
Критическая секция (critical section) —
последовательность инструкций,
в любой момент времени выполняемая
только одним потоком
Критическая секция будет выполнена
всеми потоками, но последовательно
(один за другим)
Масштабируемость с #pragma omp critical
Вычислительный узел кластера Oak
 8 ядер (два Intel Quad Xeon E5620)
 24 GiB RAM (6 x 4GB DDR3 1067 MHz)
 CentOS 6.5 x86_64, GCC 4.4.7
 Ключи компиляции: -std=c99 -O2 -fopenmp
#pragma omp parallel
{
/* ... */
for (int i = lb; i <= ub; i++) {
double f = func(a + h * (i + 0.5));
#pragma omp critical
{
sum += f;
}
}
}Замедление
Thread 0
Thread 1
Thread 2
Barrierfunc CS Wait CS
Time

Потоки ожидают освобождения
критической секции другим потоком

Код стал последовательным +
накладные расходы на потоки
Атомарные операции (atomic operations)
double integrate_omp(double (*func)(double), double a, double b, int n)
{
double h = (b - a) / n;
double sum = 0.0;
#pragma omp parallel
{
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
int items_per_thread = n / nthreads;
int lb = threadid * items_per_thread;
int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1);
for (int i = lb; i <= ub; i++) {
double f = func(a + h * (i + 0.5));
#pragma omp atomic
sum += f;
}
}
sum *= h;
return sum;
}
Атомарная операция (atomic operation) —
это инструкция процессора, в процессе выполнения
которой операнд в памяти блокируются
для других потоков
Операции: x++, x = x + y, x = x - y, x = x * y, x = x / y, ...
Масштабируемость с #pragma omp atomic
Замедление
Вычислительный узел кластера Oak
 8 ядер (два Intel Quad Xeon E5620)
 24 GiB RAM (6 x 4GB DDR3 1067 MHz)
 CentOS 6.5 x86_64, GCC 4.4.7
 Ключи компиляции: -std=c99 -O2 -fopenmp
#pragma omp parallel
{
for (int i = lb; i <= ub; i++) {
double f = func(a + h * (i + 0.5));
#pragma omp atomic
sum += f;
}
}

Теперь потоки ожидают освобождения
переменной sum (аппаратная CS)

Каждый поток выполняет ub - lb + 1
захватов переменной sum
#pragma omp atomic + локальная переменная
double integrate_omp(double (*func)(double), double a, double b, int n)
{
double h = (b - a) / n;
double sum = 0.0;
#pragma omp parallel
{
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
int items_per_thread = n / nthreads;
int lb = threadid * items_per_thread;
int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1);
double sumloc = 0.0;
for (int i = lb; i <= ub; i++)
sumloc += func(a + h * (i + 0.5));
#pragma omp atomic
sum += sumloc;
}
sum *= h;
return sum;
}
 Каждый поток накапливает сумму
в своей локальной переменной sumloc
 Затем атомарной операцией вычисляется
итоговая сумма
(всего nthreads захватов переменной sum)
#pragma omp atomic + локальная переменная
Вычислительный узел кластера Oak
 8 ядер (два Intel Quad Xeon E5620)
 24 GiB RAM (6 x 4GB DDR3 1067 MHz)
 CentOS 6.5 x86_64, GCC 4.4.7
 Ключи компиляции: -std=c99 -O2 -fopenmp
Linear scalability!
Ускорение растет
с увеличением
размера задачи
Задание
Реализовать параллельную версию программы численного интегрирования
методом прямоугольников:

написать код функции integrate_omp с использованием #pragma omp atomic и
локальной переменной (слайд 15)

оценить ускорение программы на 2, 4, 6 и 8 потоках при числе точек
интегрирования nsteps = 40 000 000 и 80 000 000
Шаблон программы находится в каталоге _task

Weitere ähnliche Inhalte

Was ist angesagt?

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

Was ist angesagt? (20)

Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)
 
Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)
 
Лекция 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 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
 
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Векторизация кода (семинар 3)
Векторизация кода (семинар 3)
 
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
 
Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
 
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
 
Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)
 
Лекция 7. Язык параллельного программирования Intel Cilk Plus
Лекция 7. Язык параллельного программирования Intel Cilk PlusЛекция 7. Язык параллельного программирования Intel Cilk Plus
Лекция 7. Язык параллельного программирования Intel Cilk Plus
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
 
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
 

Andere mochten auch

Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыAlexey Paznikov
 
Лекция 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
 
Лекция 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
 
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Mikhail Kurnosov
 
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Mikhail Kurnosov
 
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Mikhail Kurnosov
 
Лекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовЛекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовMikhail Kurnosov
 

Andere mochten auch (7)

Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
 
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
 
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
 
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
 
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
 
Лекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовЛекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмов
 

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

Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Mikhail Kurnosov
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioAndrey Karpov
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMTech Talks @NSU
 
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисленияПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисленияAlexey Paznikov
 
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...Ontico
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castRoman Orlov
 
Управление памятью в GO
Управление памятью в GOУправление памятью в GO
Управление памятью в GOssuserb5dd93
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Yandex
 
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"Fwdays
 
Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3Technopark
 
сбор урока
сбор урокасбор урока
сбор урокаLIANA180
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1Michael Karpov
 
Python и его тормоза
Python и его тормозаPython и его тормоза
Python и его тормозаAlexander Shigin
 
Back to the future: Функциональное программирование вчера и сегодня
Back to the future: Функциональное программирование вчера и сегодняBack to the future: Функциональное программирование вчера и сегодня
Back to the future: Функциональное программирование вчера и сегодняAlexander Granin
 
JS Fest 2019. Владимир Агафонкин. Быстро по умолчанию: алгоритмическое мышлен...
JS Fest 2019. Владимир Агафонкин. Быстро по умолчанию: алгоритмическое мышлен...JS Fest 2019. Владимир Агафонкин. Быстро по умолчанию: алгоритмическое мышлен...
JS Fest 2019. Владимир Агафонкин. Быстро по умолчанию: алгоритмическое мышлен...JSFestUA
 
Лекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмыЛекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмыMikhail Kurnosov
 

Ähnlich wie Семинар 2. Многопоточное программирование на OpenMP (часть 2) (20)

Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVM
 
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисленияПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
 
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_cast
 
Управление памятью в GO
Управление памятью в GOУправление памятью в GO
Управление памятью в GO
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
 
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
 
Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3
 
сбор урока
сбор урокасбор урока
сбор урока
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1
 
Python и его тормоза
Python и его тормозаPython и его тормоза
Python и его тормоза
 
Back to the future: Функциональное программирование вчера и сегодня
Back to the future: Функциональное программирование вчера и сегодняBack to the future: Функциональное программирование вчера и сегодня
Back to the future: Функциональное программирование вчера и сегодня
 
Erlang
ErlangErlang
Erlang
 
Основы SciPy
Основы SciPyОсновы SciPy
Основы SciPy
 
JS Fest 2019. Владимир Агафонкин. Быстро по умолчанию: алгоритмическое мышлен...
JS Fest 2019. Владимир Агафонкин. Быстро по умолчанию: алгоритмическое мышлен...JS Fest 2019. Владимир Агафонкин. Быстро по умолчанию: алгоритмическое мышлен...
JS Fest 2019. Владимир Агафонкин. Быстро по умолчанию: алгоритмическое мышлен...
 
Основы Python. Функции
Основы Python. ФункцииОсновы Python. Функции
Основы Python. Функции
 
Лекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмыЛекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмы
 

Mehr von 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. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)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
 
Лекция 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
 
Лекция 6. Хеш-таблицы
Лекция 6. Хеш-таблицыЛекция 6. Хеш-таблицы
Лекция 6. Хеш-таблицыMikhail Kurnosov
 

Mehr von 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)
 
Лекция 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. Хеш-таблицы
Лекция 6. Хеш-таблицыЛекция 6. Хеш-таблицы
Лекция 6. Хеш-таблицы
 

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

  • 1. Семинар 2 Стандарт OpenMP (часть 2) Михаил Курносов E-mail: mkurnosov@gmail.com WWW: www.mkurnosov.net Цикл семинаров «Основы параллельного программирования» Институт физики полупроводников им. А. В. Ржанова СО РАН Новосибирск, 2015 CC-BY
  • 2. Численное интегрирование (метод прямоугольников) f(x) x x0 ba x1 x2 x3 xn − 1 Формула средних прямоугольников const double a = -4.0; /* [a, b] */ const double b = 4.0; const int nsteps = 40000000; /* n */ double func(double x) { return exp(-x * x); } double integrate(double a, double b, int n) { double h = (b - a) / n; double sum = 0.0; for (int i = 0; i < n; i++) sum += func(a + h * (i + 0.5)); sum *= h; return sum; }
  • 3. Распараллеливание const double a = -4.0; const double b = 4.0; const int nsteps = 40000000; double func(double x) { return exp(-x * x); } double integrate(double a, double b, int n) { double h = (b - a) / n; double sum = 0.0; for (int i = 0; i < n; i++) sum += func(a + h * (i + 0.5)); sum *= h; return sum; }  Итерации цикла for распределим между потоками  Каждый поток вычисляет часть суммы (площади)  Варианты распределения итераций (точек) между p потоками: T0 T0 T0 T0 T1 T1 T1 T1 T2 T2 T2 T2 Thread 0 Thread 1 Thread 2 T0 T1 T2 T0 T1 T2 T0 T1 T2 T0 T1 T2 Thread 0, Thread1, Thread 2, Thread 0, Thread 1, Thread 2, ... 1) Разбиение на p смежных непрерывных частей 2) Циклическое распределение итераций по потокам
  • 4. Параллельная версия double integrate_omp(double (*func)(double), double a, double b, int n) { double h = (b - a) / n; double sum = 0.0; #pragma omp parallel { int nthreads = omp_get_num_threads(); int threadid = omp_get_thread_num(); int items_per_thread = n / nthreads; int lb = threadid * items_per_thread; int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1); for (int i = lb; i <= ub; i++) sum += func(a + h * (i + 0.5)); } sum *= h; return sum; } T0 T0 T0 T0 T1 T1 T1 T1 T2 T2 T2 T2 Thread 0 Thread 1 Thread 2 Разбиение пространства итераций на смежные непрерывные части lb ub
  • 5. Параллельная версия (продолжение) const double PI = 3.14159265358979323846; const double a = -4.0; const double b = 4.0; const int nsteps = 40000000; double run_serial() { double t = wtime(); double res = integrate(func, a, b, nsteps); t = wtime() - t; printf("Result (serial): %.12f; error %.12fn", res, fabs(res - sqrt(PI))); return t; } double run_parallel() { double t = wtime(); double res = integrate_omp(func, a, b, nsteps); t = wtime() - t; printf("Result (parallel): %.12f; error %.12fn", res, fabs(res - sqrt(PI))); return t; } int main(int argc, char **argv) { printf("Integration f(x) on [%.12f, %.12f], nsteps = %dn", a, b, nsteps); double tserial = run_serial(); double tparallel = run_parallel(); printf("Execution time (serial): %.6fn", tserial); printf("Execution time (parallel): %.6fn", tparallel); printf("Speedup: %.2fn", tserial / tparallel); return 0; }
  • 6. Компиляция и запуск $ make gcc -std=c99 -Wall -O2 -fopenmp -c integrate.c -o integrate.o gcc -o integrate integrate.o -lm -fopenmp $ export OMP_NUM_THREADS=4 $ ./integrate Result (serial): 1.772453823579; error 0.000000027326 Result (parallel): 0.896639185158; error 0.875814665748 $ ./integrate Result (serial): 1.772453823579; error 0.000000027326 Result (parallel): 0.794717040479; error 0.977736810426 $ ./integrate Result (serial): 1.772453823579; error 0.000000027326 Result (parallel): 0.771561715425; error 1.000892135481 На каждом запуске разные результаты! В чем причина?
  • 7. Состояние гонки данных (race condition, data race) double integrate_omp(double (*func)(double), double a, double b, int n) { double h = (b - a) / n; double sum = 0.0; #pragma omp parallel { int nthreads = omp_get_num_threads(); int threadid = omp_get_thread_num(); int items_per_thread = n / nthreads; int lb = threadid * items_per_thread; int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1); for (int i = lb; i <= ub; i++) sum += func(a + h * (i + 0.5)); } sum *= h; return sum; } Ошибка - race condition  Несколько потоков одновременно читают и записывают переменную sum  Значение sum зависит от порядка выполнения потоков
  • 8. Состояние гонки данных (race condition, data race) Два потока одновременно увеличивают значение переменной x на 1 (начальное значение x = 0) Thread 0 x = x + 1; Thread 1 x = x + 1; Ожидаемый (идеальный) порядок выполнения потоков: первый поток увеличил x, затем второй Time Thread 0 Thread 1 x 0 Значение x = 0 загружается в регистр R процессора 0 1 Значение 0 в регистре R увеличивается на 1 0 2 Значение 1 из регистра R записывается в x 1 3 Значение x = 1 загружается в регистр R процессора 1 4 Значение 1 в регистре R увеличивается на 1 1 5 Значение 2 из регистра R записывается в x 2 Ошибки нет
  • 9. Состояние гонки данных (race condition, data race) Два потока одновременно увеличивают значение переменной x на 1 (начальное значение x = 0) Thread 0 x = x + 1; Thread 1 x = x + 1; Реальный порядок выполнения потоков (недетерминированный) (потоки могут выполняться в любой последовательности, приостанавливаться и запускаться) Time Thread 0 Thread 1 x 0 Значение x = 0 загружается в регистр R процессора 0 1 Значение 0 в регистре R увеличивается на 1 Значение x = 0 загружается в регистр R процессора 0 2 Значение 1 из регистра R записывается в x Значение 1 в регистре R увеличивается на 1 1 3 Значение 1 из регистра R записывается в x 1 Ошибка - data race (ожидали 2)
  • 10. Устранение гонки данных double integrate_omp(double (*func)(double), double a, double b, int n) { double h = (b - a) / n; double sum = 0.0; #pragma omp parallel { int nthreads = omp_get_num_threads(); int threadid = omp_get_thread_num(); int items_per_thread = n / nthreads; int lb = threadid * items_per_thread; int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1); for (int i = lb; i <= ub; i++) sum += func(a + h * (i + 0.5)); } sum *= h; return sum; } Надо сделать так, чтобы увеличение переменной sum в любой момент времени выполнялось только одним потоком
  • 11. Критическая секция (critical section) double integrate_omp(double (*func)(double), double a, double b, int n) { double h = (b - a) / n; double sum = 0.0; #pragma omp parallel { int nthreads = omp_get_num_threads(); int threadid = omp_get_thread_num(); int items_per_thread = n / nthreads; int lb = threadid * items_per_thread; int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1); for (int i = lb; i <= ub; i++) { double f = func(a + h * (i + 0.5)); #pragma omp critical { sum += f; } } } sum *= h; return sum; } Критическая секция (critical section) — последовательность инструкций, в любой момент времени выполняемая только одним потоком Критическая секция будет выполнена всеми потоками, но последовательно (один за другим)
  • 12. Масштабируемость с #pragma omp critical Вычислительный узел кластера Oak  8 ядер (два Intel Quad Xeon E5620)  24 GiB RAM (6 x 4GB DDR3 1067 MHz)  CentOS 6.5 x86_64, GCC 4.4.7  Ключи компиляции: -std=c99 -O2 -fopenmp #pragma omp parallel { /* ... */ for (int i = lb; i <= ub; i++) { double f = func(a + h * (i + 0.5)); #pragma omp critical { sum += f; } } }Замедление Thread 0 Thread 1 Thread 2 Barrierfunc CS Wait CS Time  Потоки ожидают освобождения критической секции другим потоком  Код стал последовательным + накладные расходы на потоки
  • 13. Атомарные операции (atomic operations) double integrate_omp(double (*func)(double), double a, double b, int n) { double h = (b - a) / n; double sum = 0.0; #pragma omp parallel { int nthreads = omp_get_num_threads(); int threadid = omp_get_thread_num(); int items_per_thread = n / nthreads; int lb = threadid * items_per_thread; int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1); for (int i = lb; i <= ub; i++) { double f = func(a + h * (i + 0.5)); #pragma omp atomic sum += f; } } sum *= h; return sum; } Атомарная операция (atomic operation) — это инструкция процессора, в процессе выполнения которой операнд в памяти блокируются для других потоков Операции: x++, x = x + y, x = x - y, x = x * y, x = x / y, ...
  • 14. Масштабируемость с #pragma omp atomic Замедление Вычислительный узел кластера Oak  8 ядер (два Intel Quad Xeon E5620)  24 GiB RAM (6 x 4GB DDR3 1067 MHz)  CentOS 6.5 x86_64, GCC 4.4.7  Ключи компиляции: -std=c99 -O2 -fopenmp #pragma omp parallel { for (int i = lb; i <= ub; i++) { double f = func(a + h * (i + 0.5)); #pragma omp atomic sum += f; } }  Теперь потоки ожидают освобождения переменной sum (аппаратная CS)  Каждый поток выполняет ub - lb + 1 захватов переменной sum
  • 15. #pragma omp atomic + локальная переменная double integrate_omp(double (*func)(double), double a, double b, int n) { double h = (b - a) / n; double sum = 0.0; #pragma omp parallel { int nthreads = omp_get_num_threads(); int threadid = omp_get_thread_num(); int items_per_thread = n / nthreads; int lb = threadid * items_per_thread; int ub = (threadid == nthreads - 1) ? (n - 1) : (lb + items_per_thread - 1); double sumloc = 0.0; for (int i = lb; i <= ub; i++) sumloc += func(a + h * (i + 0.5)); #pragma omp atomic sum += sumloc; } sum *= h; return sum; }  Каждый поток накапливает сумму в своей локальной переменной sumloc  Затем атомарной операцией вычисляется итоговая сумма (всего nthreads захватов переменной sum)
  • 16. #pragma omp atomic + локальная переменная Вычислительный узел кластера Oak  8 ядер (два Intel Quad Xeon E5620)  24 GiB RAM (6 x 4GB DDR3 1067 MHz)  CentOS 6.5 x86_64, GCC 4.4.7  Ключи компиляции: -std=c99 -O2 -fopenmp Linear scalability! Ускорение растет с увеличением размера задачи
  • 17. Задание Реализовать параллельную версию программы численного интегрирования методом прямоугольников:  написать код функции integrate_omp с использованием #pragma omp atomic и локальной переменной (слайд 15)  оценить ускорение программы на 2, 4, 6 и 8 потоках при числе точек интегрирования nsteps = 40 000 000 и 80 000 000 Шаблон программы находится в каталоге _task