SlideShare uma empresa Scribd logo
1 de 14
Baixar para ler offline
Семинар 3
Стандарт OpenMP (часть 3)
Михаил Курносов
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;
}
#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
 Затем атомарной операцией вычисляется
итоговая сумма
Вручную определяем диапазон
[lb, ub] значений i для каждого потока
Распараллеливание циклов (#pragma omp for)
double integrate_omp(double (*func)(double), double a, double b, int n)
{
double h = (b - a) / n;
double sum = 0.0;
#pragma omp parallel
{
double sumloc = 0.0;
#pragma omp for
for (int i = 0; i < n; i++)
sumloc += func(a + h * (i + 0.5));
#pragma omp atomic
sum += sumloc;
}
sum *= h;
return sum;
}
Разбивает пространство итераций на nthreads
непрерывных смежных интервалов
T0 T0 T0 T0 T1 T1 T1 T1 T2 T2 T2 T2
Thread 0 Thread 1 Thread 2
Разбиение пространства итераций
на смежные непрерывные части
i=0 i=n-1
Распределение итераций по потокам
#pragma omp for
for (int i = 0; i < n; i++)
#pragma omp for schedule(static, k)
for (int i = 0; i < n; i++)
Разбиение на p смежных непрерывных диапазона
 Первым p - r потокам достается по q итераций, остальным r
потокам — по q - 1
 Пример для p = 3, n = 10 (n = 3 * 4 - 2):
0 0 0 0 1 1 1 2 2 2
Обозначения:
 p — число потоков в параллельном регионе (nthreads)
 q = ceil(n / p)
 n = p * q - r
Циклическое распределение итераций (round-robin)
 Первые k итераций достаются потоку 0, следующие k
итераций потоку 1, ..., k итераций потоку p - 1, и заново k
итераций потоку 0 и т.д.
 Пример для p = 3, n = 10, k = 1 (n = 3 * 4 - 2):
0 1 2 0 1 2 0 1 2 0
Распределение итераций по потокам
#pragma omp for schedule(dynamic, k)
for (int i = 0; i < n; i++)
#pragma omp for schedule(guided, k)
for (int i = 0; i < n; i++)
Динамическое выделение блоков по k итераций
 Потоки получают по k итераций, по окончанию их обработки
запрашивают еще k итераций и т.д.
 Заранее неизвестно какие итерации достанутся потокам
(зависит от порядка и длительности их выполнения)
Обозначения:
 p — число потоков в параллельном регионе (nthreads)
 q = ceil(n / p)
 n = p * q - r
Динамическое выделение уменьшающихся блоков
 Каждый поток получает n / p итераций
 По окончанию их обработки, из оставшихся n' итераций поток
запрашивает n' / p
Подсчет количества простых чисел
Подсчитывает количество
простых числе в интервале [a, b]
Определят, является ли
число n простым
const int a = 1;
const int b = 10000000;
int is_prime_number(int n)
{
int limit = sqrt(n) + 1;
for (int i = 2; i <= limit; i++) {
if (n % i == 0)
return 0;
}
return (n > 1) ? 1 : 0;
}
int count_prime_numbers(int a, int b)
{
int nprimes = 0;
if (a <= 2) {
nprimes = 1; /* Count '2' as a prime number */
a = 2;
}
if (a % 2 == 0) /* Shift 'a' to odd number */
a++;
/* Loop over odd numbers: a, a + 2, a + 4, ... , b */
for (int i = a; i <= b; i += 2) {
if (is_prime_number(i))
nprimes++;
}
return nprimes;
}
Подсчет количества простых чисел (OpenMP)
Разбили интервал [a, b] проверяемых чисел
на смежные непрерывные отрезки
int count_prime_numbers_omp(int a, int b)
{
int nprimes = 0;
if (a <= 2) {
nprimes = 1; /* Count '2' as a prime number */
a = 2;
}
if (a % 2 == 0) /* Shift 'a' to odd number */
a++;
#pragma omp parallel
{
int nloc = 0;
/* Loop over odd numbers: a, a + 2, a + 4, ... , b */
#pragma omp for
for (int i = a; i <= b; i += 2) {
if (is_prime_number(i))
nloc++;
}
#pragma omp atomic
nprimes += nloc;
}
return nprimes;
}
Неравномерная загрузка потоков (load imbalance)
$ OMP_NUM_THREADS=4 ./primes
Count prime numbers on [1, 10000000]
Result (serial): 664579
Thread 0 execution time: 1.789976
Thread 1 execution time: 2.961944
Thread 2 execution time: 3.004635
Thread 3 execution time: 3.588935
Result (parallel): 664579
Execution time (serial): 7.190282
Execution time (parallel): 3.590609
Speedup: 2.00
Потоки загружены не равномерно (load imbalance) —
потоки с большими номерами выполняются дольше
Причина?
Load
imbalance
int count_prime_numbers_omp(int a, int b)
{
int nprimes = 0;
if (a <= 2) {
nprimes = 1;
a = 2;
}
if (a % 2 == 0)
a++;
#pragma omp parallel
{
double t = omp_get_wtime();
int nloc = 0;
#pragma omp for nowait
for (int i = a; i <= b; i += 2) {
if (is_prime_number(i))
nloc++;
} /* 'nowait' disables barrier after for */
#pragma omp atomic
nprimes += nloc;
t = omp_get_wtime() - t;
printf("Thread %d execution time: %.6f sec.n",
omp_get_thread_num(), t);
}
return nprimes;
}
Неравномерная загрузка потоков (load imbalance)
 Время выполнения функции is_prime_number(i) зависит от значения i
 Потокам с большими номерами достались большие значения i
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3
Неэффективное распределение итераций по потокам
int count_prime_numbers_omp(int a, int b)
{
int nprimes = 0;
if (a <= 2) {
nprimes = 1; /* Count '2' as a prime number */
a = 2;
}
if (a % 2 == 0) /* Shift 'a' to odd number */
a++;
#pragma omp parallel
{
int nloc = 0;
/* Loop over odd numbers: a, a + 2, a + 4, ... , b */
#pragma omp for
for (int i = a; i <= b; i += 2) {
if (is_prime_number(i))
nloc++;
}
#pragma omp atomic
nprimes += nloc;
}
return nprimes;
}
Динамическое распределение итераций
int count_prime_numbers_omp(int a, int b)
{
int nprimes = 0;
if (a <= 2) {
nprimes = 1; /* Count '2' as a prime number */
a = 2;
}
if (a % 2 == 0) /* Shift 'a' to odd number */
a++;
#pragma omp parallel
{
int nloc = 0;
/* Loop over odd numbers: a, a + 2, a + 4, ... , b */
#pragma omp for schedule(dynamic,100) nowait
for (int i = a; i <= b; i += 2) {
if (is_prime_number(i))
nloc++;
} /* 'nowait' disables barrier after for */
#pragma omp atomic
nprimes += nloc;
}
return nprimes;
}
Динамическое распределение
итераций блоками по 100 элементов
Анализ эффективности
Вычислительный узел кластера Oak (NUMA)
 8 ядер (два Intel Quad Xeon E5620)
 24 GiB RAM (6 x 4GB DDR3 1067 MHz)
 CentOS 6.5 x86_64 (kernel 2.6.32), GCC 4.4.7
a = 1, b = 10000000
Вычислительный узел кластера Jet (SMP)
 8 ядер (два Intel Quad Xeon E5420)
 8 GiB RAM
 Fedora 20 x86_64 (kernel 3.11.10), GCC 4.8.3
a = 1, b = 10000000
gcc 4.4.7 gcc 4.8.3
Привязка потоков к процессорам
export GOMP_CPU_AFFINITY="0-7"
export OMP_NUM_THREADS=8
./primes
Задание
Реализовать параллельную версию программы подсчета числа простых чисел
в заданном интервале
 написать код функции count_prime_numbers_omp с использованием
#pragma omp for и локальной переменной (слайд 11)
 добиться равномерной загрузки потоков, оценить ускорение программы
на 2, 4, 6 и 8 потоках
Шаблон программы находится в каталоге _task

Mais conteúdo relacionado

Mais procurados

Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Mikhail Kurnosov
 
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Mikhail Kurnosov
 
Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10
Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10
Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10
Mikhail Kurnosov
 
Лекция 4: Стек. Очередь
Лекция 4: Стек. ОчередьЛекция 4: Стек. Очередь
Лекция 4: Стек. Очередь
Mikhail Kurnosov
 

Mais procurados (20)

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

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

Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Mikhail Kurnosov
 
Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3
Technopark
 
чернякова г.в.
чернякова г.в.чернякова г.в.
чернякова г.в.
sharikdp
 
Лекция 13: Трудноразрешимые задачи. NP-полнота.
Лекция 13: Трудноразрешимые задачи. NP-полнота.Лекция 13: Трудноразрешимые задачи. NP-полнота.
Лекция 13: Трудноразрешимые задачи. NP-полнота.
Mikhail Kurnosov
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
etyumentcev
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
Eugeniy Tyumentcev
 
Лекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмыЛекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмы
Mikhail Kurnosov
 
Лекция 11: Методы разработки алгоритмов
Лекция 11: Методы разработки алгоритмовЛекция 11: Методы разработки алгоритмов
Лекция 11: Методы разработки алгоритмов
Mikhail Kurnosov
 
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
Ontico
 
презентации продолжение банкета
презентации продолжение банкетапрезентации продолжение банкета
презентации продолжение банкета
student_kai
 

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

Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
 
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
 
Основы SciPy
Основы SciPyОсновы SciPy
Основы SciPy
 
Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3
 
чернякова г.в.
чернякова г.в.чернякова г.в.
чернякова г.в.
 
Лекция 13: Трудноразрешимые задачи. NP-полнота.
Лекция 13: Трудноразрешимые задачи. NP-полнота.Лекция 13: Трудноразрешимые задачи. NP-полнота.
Лекция 13: Трудноразрешимые задачи. NP-полнота.
 
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисленияПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVM
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_cast
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
 
Diskretn analiz
Diskretn analizDiskretn analiz
Diskretn analiz
 
Diskretn analiz
Diskretn analizDiskretn analiz
Diskretn analiz
 
Лекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмыЛекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмы
 
Лекция 11: Методы разработки алгоритмов
Лекция 11: Методы разработки алгоритмовЛекция 11: Методы разработки алгоритмов
Лекция 11: Методы разработки алгоритмов
 
Лекция 13 Теоретико-числовые алгоритмы Часть 2
Лекция 13 Теоретико-числовые алгоритмы Часть 2Лекция 13 Теоретико-числовые алгоритмы Часть 2
Лекция 13 Теоретико-числовые алгоритмы Часть 2
 
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
 
лекция 1
лекция 1лекция 1
лекция 1
 
презентации продолжение банкета
презентации продолжение банкетапрезентации продолжение банкета
презентации продолжение банкета
 

Mais de Mikhail Kurnosov

Mais de Mikhail Kurnosov (18)

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

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

  • 1. Семинар 3 Стандарт OpenMP (часть 3) Михаил Курносов 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. #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  Затем атомарной операцией вычисляется итоговая сумма Вручную определяем диапазон [lb, ub] значений i для каждого потока
  • 4. Распараллеливание циклов (#pragma omp for) double integrate_omp(double (*func)(double), double a, double b, int n) { double h = (b - a) / n; double sum = 0.0; #pragma omp parallel { double sumloc = 0.0; #pragma omp for for (int i = 0; i < n; i++) sumloc += func(a + h * (i + 0.5)); #pragma omp atomic sum += sumloc; } sum *= h; return sum; } Разбивает пространство итераций на nthreads непрерывных смежных интервалов T0 T0 T0 T0 T1 T1 T1 T1 T2 T2 T2 T2 Thread 0 Thread 1 Thread 2 Разбиение пространства итераций на смежные непрерывные части i=0 i=n-1
  • 5. Распределение итераций по потокам #pragma omp for for (int i = 0; i < n; i++) #pragma omp for schedule(static, k) for (int i = 0; i < n; i++) Разбиение на p смежных непрерывных диапазона  Первым p - r потокам достается по q итераций, остальным r потокам — по q - 1  Пример для p = 3, n = 10 (n = 3 * 4 - 2): 0 0 0 0 1 1 1 2 2 2 Обозначения:  p — число потоков в параллельном регионе (nthreads)  q = ceil(n / p)  n = p * q - r Циклическое распределение итераций (round-robin)  Первые k итераций достаются потоку 0, следующие k итераций потоку 1, ..., k итераций потоку p - 1, и заново k итераций потоку 0 и т.д.  Пример для p = 3, n = 10, k = 1 (n = 3 * 4 - 2): 0 1 2 0 1 2 0 1 2 0
  • 6. Распределение итераций по потокам #pragma omp for schedule(dynamic, k) for (int i = 0; i < n; i++) #pragma omp for schedule(guided, k) for (int i = 0; i < n; i++) Динамическое выделение блоков по k итераций  Потоки получают по k итераций, по окончанию их обработки запрашивают еще k итераций и т.д.  Заранее неизвестно какие итерации достанутся потокам (зависит от порядка и длительности их выполнения) Обозначения:  p — число потоков в параллельном регионе (nthreads)  q = ceil(n / p)  n = p * q - r Динамическое выделение уменьшающихся блоков  Каждый поток получает n / p итераций  По окончанию их обработки, из оставшихся n' итераций поток запрашивает n' / p
  • 7. Подсчет количества простых чисел Подсчитывает количество простых числе в интервале [a, b] Определят, является ли число n простым const int a = 1; const int b = 10000000; int is_prime_number(int n) { int limit = sqrt(n) + 1; for (int i = 2; i <= limit; i++) { if (n % i == 0) return 0; } return (n > 1) ? 1 : 0; } int count_prime_numbers(int a, int b) { int nprimes = 0; if (a <= 2) { nprimes = 1; /* Count '2' as a prime number */ a = 2; } if (a % 2 == 0) /* Shift 'a' to odd number */ a++; /* Loop over odd numbers: a, a + 2, a + 4, ... , b */ for (int i = a; i <= b; i += 2) { if (is_prime_number(i)) nprimes++; } return nprimes; }
  • 8. Подсчет количества простых чисел (OpenMP) Разбили интервал [a, b] проверяемых чисел на смежные непрерывные отрезки int count_prime_numbers_omp(int a, int b) { int nprimes = 0; if (a <= 2) { nprimes = 1; /* Count '2' as a prime number */ a = 2; } if (a % 2 == 0) /* Shift 'a' to odd number */ a++; #pragma omp parallel { int nloc = 0; /* Loop over odd numbers: a, a + 2, a + 4, ... , b */ #pragma omp for for (int i = a; i <= b; i += 2) { if (is_prime_number(i)) nloc++; } #pragma omp atomic nprimes += nloc; } return nprimes; }
  • 9. Неравномерная загрузка потоков (load imbalance) $ OMP_NUM_THREADS=4 ./primes Count prime numbers on [1, 10000000] Result (serial): 664579 Thread 0 execution time: 1.789976 Thread 1 execution time: 2.961944 Thread 2 execution time: 3.004635 Thread 3 execution time: 3.588935 Result (parallel): 664579 Execution time (serial): 7.190282 Execution time (parallel): 3.590609 Speedup: 2.00 Потоки загружены не равномерно (load imbalance) — потоки с большими номерами выполняются дольше Причина? Load imbalance int count_prime_numbers_omp(int a, int b) { int nprimes = 0; if (a <= 2) { nprimes = 1; a = 2; } if (a % 2 == 0) a++; #pragma omp parallel { double t = omp_get_wtime(); int nloc = 0; #pragma omp for nowait for (int i = a; i <= b; i += 2) { if (is_prime_number(i)) nloc++; } /* 'nowait' disables barrier after for */ #pragma omp atomic nprimes += nloc; t = omp_get_wtime() - t; printf("Thread %d execution time: %.6f sec.n", omp_get_thread_num(), t); } return nprimes; }
  • 10. Неравномерная загрузка потоков (load imbalance)  Время выполнения функции is_prime_number(i) зависит от значения i  Потокам с большими номерами достались большие значения i 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 Неэффективное распределение итераций по потокам int count_prime_numbers_omp(int a, int b) { int nprimes = 0; if (a <= 2) { nprimes = 1; /* Count '2' as a prime number */ a = 2; } if (a % 2 == 0) /* Shift 'a' to odd number */ a++; #pragma omp parallel { int nloc = 0; /* Loop over odd numbers: a, a + 2, a + 4, ... , b */ #pragma omp for for (int i = a; i <= b; i += 2) { if (is_prime_number(i)) nloc++; } #pragma omp atomic nprimes += nloc; } return nprimes; }
  • 11. Динамическое распределение итераций int count_prime_numbers_omp(int a, int b) { int nprimes = 0; if (a <= 2) { nprimes = 1; /* Count '2' as a prime number */ a = 2; } if (a % 2 == 0) /* Shift 'a' to odd number */ a++; #pragma omp parallel { int nloc = 0; /* Loop over odd numbers: a, a + 2, a + 4, ... , b */ #pragma omp for schedule(dynamic,100) nowait for (int i = a; i <= b; i += 2) { if (is_prime_number(i)) nloc++; } /* 'nowait' disables barrier after for */ #pragma omp atomic nprimes += nloc; } return nprimes; } Динамическое распределение итераций блоками по 100 элементов
  • 12. Анализ эффективности Вычислительный узел кластера Oak (NUMA)  8 ядер (два Intel Quad Xeon E5620)  24 GiB RAM (6 x 4GB DDR3 1067 MHz)  CentOS 6.5 x86_64 (kernel 2.6.32), GCC 4.4.7 a = 1, b = 10000000 Вычислительный узел кластера Jet (SMP)  8 ядер (два Intel Quad Xeon E5420)  8 GiB RAM  Fedora 20 x86_64 (kernel 3.11.10), GCC 4.8.3 a = 1, b = 10000000 gcc 4.4.7 gcc 4.8.3
  • 13. Привязка потоков к процессорам export GOMP_CPU_AFFINITY="0-7" export OMP_NUM_THREADS=8 ./primes
  • 14. Задание Реализовать параллельную версию программы подсчета числа простых чисел в заданном интервале  написать код функции count_prime_numbers_omp с использованием #pragma omp for и локальной переменной (слайд 11)  добиться равномерной загрузки потоков, оценить ускорение программы на 2, 4, 6 и 8 потоках Шаблон программы находится в каталоге _task