
Лекции / Лекция 3
.docТехнологии и методы программирования. Лекция 3.
Управление распределением вычислительной нагрузки в цикле.
Openmp содержит эффективные средства управления распределением итераций по потокам. Оно обеспечивается с помощью директивы shedule(<тип>[,N (количество итераций в блоках)]). Существует 5 режимов работы с итерациями:
Если shedule отсутствует — по умолчанию, в зависимости от настроек и окружения. Умолчания разные в разных компиляторах, как и настройки среды.
1) static([N]) - статическое распределение итераций по параллельным блокам. Если N указано, то 0-ой поток обрабатывает первые N итераций, 1-ый — следующие N и так далее. Если после распределения итераций последнему потоку итерации ещё остались, то всё повторяется — 0-ой поток снова получает N итераций, 1-ый = следующие N... В последней порции может быть и меньше N итераций. Если же N не указан, то все итерации делятся между потоками на примерно равные блоки. В спецификации нет стандарта на распределение «примерно равных» блоков, поэтому оно зависит от реализации.
Пример распределения итераций по потокам:
100 итераций и 4 потока |
|||
0 |
1 |
2 |
3 |
25 |
25 |
25 |
25 |
110 итераций и 4 потока |
|||
0 |
1 |
2 |
3 |
28 |
28 |
27 |
27 |
(Итерации выполняются потоками последовательно)
2) dynamic[N] – динамическое распределение, при котором блоки итераций распределяются по требованию: первый из свободных потоков получает свою порцию итераций, затем — второй, и так далее. Последняя порция может содержать и меньше N операций. Если N не задано, оно по умолчанию принимается равным 1.
3) guided[N] – тоже режим динамического распределения блоков итераций по запросу свободных потоков. В отличие от dynamic блоки изменяются по объёму, вычисляясь при каждом обращении, но не может быть меньше N (или 1, если N не задано). Размер блока определяется количеством не разобранных другими потоками итераций, делённому на число потоков.
Пример:
110 итераций, 4 потока.
Первый поток получает 27 итераций.
Второй — (110-27)/4=20 итераций
Третий — (110-27-20)/4=15 итераций, и так далее.
Размер последнего блока может быть и меньше N – в зависимости от того, сколько итераций осталось. В целом, у guided лучший баланс вычислительной нагрузки по потокам.
4) runtime – способ распределения итераций, определяющийся во время исполнения программы. То, какой способ будет выбран, зависит от значения переменной окружения OMP_SHEDULE. Если же оно не определено/несовместимо с данной системой исполнения, то результат зависит от настроек умолчаний. Режим используется для того, чтобы настраивать режимы распределения итераций во время работы программы.
5) auto – режим распределения итераций определяется компилятором или системой исполнения (данный режим игнорирует N и OMP_SHEDULE)
Пример:
#include <stdio.h>
#include <omp.h>
int main (int argc, char** argv[])
{
int I;
#pragma omp parallel privete(i)
# pragma omp parallel for shedule(X)
for(i=0; i<10; i++)
{
//вывод номера потока и итерации
}
}
Итерации\Х |
static |
static,1 |
static, 2 |
dynamic |
dynamic, 2 |
guided |
guided, 2 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
2 |
0 |
2 |
0 |
2 |
1 |
2 |
1 |
1 |
1 |
3 |
1 |
3 |
1 |
3 |
1 |
3 |
1 |
4 |
1 |
0 |
2 |
1 |
2 |
1 |
2 |
5 |
1 |
1 |
2 |
3 |
2 |
2 |
2 |
6 |
2 |
2 |
3 |
2 |
3 |
3 |
3 |
7 |
2 |
3 |
3 |
0 |
3 |
0 |
3 |
8 |
3 |
0 |
0 |
1 |
3 |
0 |
0 |
9 |
3 |
1 |
0 |
0 |
3 |
3 |
0 |
Наибольший дисбаланс — static,2, dynamic, 2, guided, 2 - один из потоков выполнял на 2 операции больше прочих.
Баланс распределения — решающий момент в достижении целей параллельного программирования.
Замечание: Чтобы узнать, какой режим задан OMP_SHEDULE, используется функция void omp_get_shedule(omp_shed_t* type, int chunk), где type– выходной параметр, chunk – N. Для установки OMP_SHEDULE используется функция void omp_set_shedule(omp_shed_t type, int chunk). Не все значения возможно установить — это зависит от версии. Почти всегда можно static 1, dynamic 2, guided 3.
Требования:
При распараллеливании цикла важно убедиться, что итерации независимы. Алгоритм — узкое место в параллельном программировании.
Замечание:
Счётчик в распараллеленом цикле становится локальной переменной.
Помимо shedule, директива for может иметь опции private, first_private, last_private, redaction, collapse(N). Последняя отвечает за глубину распараллеливания цикла: в случае, если она не указана, директива for распараллелит только внешний цикл, а с ней — итерации циклов от верхнего до N-1 вложенного образуют единое пространство, которое и будет распараллелено.