Presentation is loading. Please wait.

Presentation is loading. Please wait.

Программирование в OpenMP ЛЕКЦИЯ №5 Калинина А.П..

Similar presentations


Presentation on theme: "Программирование в OpenMP ЛЕКЦИЯ №5 Калинина А.П.."— Presentation transcript:

1 Программирование в OpenMP ЛЕКЦИЯ №5 Калинина А.П.

2 2 Структура OpenMP Набор директив компилятора Библиотека функций Набор переменных окружения Слайд из лекции В.П. Гергеля

3 3 Структура OpenMP Слайд openmp.org, Programming OpenMP

4 4 OpenMP «Вилочный» параллелелизм: «Мастер» - поток создает команду потоков Последовательная программа преображается в параллельную Параллельные регионы «Мастер»

5 5 Синтаксис OpenMP* Большинство конструкций OpenMP* являются директивами компилятора (pragmas). Для C и C++ общий вид директив: #pragma omp construct [clause [clause]…]

6 6 OpenMP Часть компилятора Дополнительные указания компилятору в том ключе, каким образом можно убрать зависимость по данным в конкретном участке кода и распараллелить способом, стандартным для данного компилятора Наиболее эффективно для реализации явных параллельных конструкций Затраты на синхронизацию кода очень велики – «RunTime» невыгоден

7 7 «Метод успешного многопоточного программирования в OpenMP» 40% успеха – выбор удачного алгоритма решения задачи – полный параллелелизм, без объектов синхронизации, в крайнем случае – на уровне элементарных операций 40% успеха – выбор удачных структур данных упаковка информации, которая будет передаваться потокам на выполнение, в минимальный объем, («плотный квант информации» или строка кэша с максимальным КПД) Информация, необходимая для выполнения кода любого региона, расположена «рядом» 15% успеха – оптимизация последовательного кода – ключи компиляции, оптимизация под процессор, возможность векторизации и т.д. – возможность этого часто зависит от предыдущих пунктов 5% успеха – конструкции OpenMP

8 8 95% успеха Оптимизированная последовательная программ, пригодная для эффективного распараллеливания

9 9 Примеры распараллеливания с помощью OpenMP Преобразование Фурье Поиск кратчайших путей на разреженном графе Умножение матриц (автор кода О. Нечаева, НГУ, лаборатория Intel) Задача Дирихле (код из курса В.П. Гергеля)

10 10 Преобразование Фурье Схема «ветвь» или «бабочка» - поочередное вычисление всех коэффициентов (распараллеливается) или одновременное (тоже распараллеливается) ? схема «бабочка» с применением возведения в степень методом побитового сдвига на порядок быстрее «ветви» Последовательный код «бабочки»: перегруппировка данных перед началом вычислений или в конце? перегруппировка данных перед началом вычислений дает ускорение в 1,5 раза Конструкции OpenMP – ускорение примерно в 1,9 раза

11 11 Задание 1. Откройте проект fft_all_variants 2. Аргументы командной строки – степень 2, номер алгоритма, число потоков. 1,2,3,7 – последовательные алгоритмы, 4,5,6 – параллельные Алгоритмы 1,4 – «бабочка» последовательная и параллельная с предварительной перегруппировкой Алгоритмы 1,4 – «бабочка» последовательная и параллельная без предварительной перегруппировки Алгоритмы 3,6 – «ветвь» последовательная и параллельная без применения операции возведения в степень методом побитового сдвига 3. Определите ускорение для всех вариантов

12 12 Конструкции OpenMP в преобразовании Фурье start = rdtsc(); //start time for( i = 0 ; i < power ; i++ )//steps { #pragma omp parallel for private (index) for( j = 0 ; j < num_points ; j++) { index = j << (i + 1); fft_index(offset, num_points, index, arg, arg_2, f_Re, f_Im); } num_points >>= 1; offset <<= 1; }//end of fft algorithm stop = rdtsc()-start;

13 13 Создание проекта Debug c OpenMP в Visual Studio – процесс отладки 1.Создать пустой проект – вкладка «Debug» 2.Вставить в него код из файла файл.cpp 3.Установить: Properties-> C/C++ -> Code generation -> Multythreaded Debug DLL Properties-> C/C++ ->Language -> Process OpenMP Directive - Generate Parallel Code Никакой оптимизации не должно быть! Код «инструментирован отладочной информацией»

14 14 Создание проекта Release c OpenMP в Visual Studio – измерение производительности 1.Создать пустой проект – вкладка «Release» 2.Вставить в него код из файла файл.cpp 3.Установить: Properties-> C/C++ -> Code generation -> Multythreaded DLL Properties-> C/C++ ->Language -> Process OpenMP Directive - Generate Parallel Code Установить режимы оптимизации! Properties-> C/C++ ->Optimization

15 15 Требования к защищаемой индивидуальной задаче Код: несколько вариантов последовательного и параллельного кода в одном проекте возможность вызова любого варианта кода с помощью аргумента командной строки Презентация: краткое описание основных последовательных и параллельных алгоритмов Диагностика инструментов Результаты измерения времени работы параллельных и последовательных вариантов

16 16 Поиск кратчайших путей на разреженном графе Как представлять граф – матрицей весов одномерными массивами точек, имеющих связи Разреженный граф – выгоднее парами смежных точек – для малой размерности ускорение 20%, большую размерность матрицей вообще моделировать невозможно Алгоритм Дейкстры: что определять в начале: является ли кратчайший путь известным - вероятность 50% является ли точка соседом «реперной точки» -вероятность меньше 1% - лучше сначала это условие – 30% ускорения за счет правильного порядка

17 17 Конструкции OpenMP для графа for (i = 1; i < treeData.N; i++)//__evaluation of the shortest path to the one of the nodes { omp_set_num_threads (num_threads); #pragma omp parallel private(id) {id = omp_get_thread_num(); Path_Min[id] = Search_minimum (id, treeData.max, treeData.Path, treeData.N, num_threads ); } Nomer_nmin = Path_Min[0]; MinimPath = treeData.Path[Nomer_nmin]; for (j = 0; j < num_threads; j++) {Nomer_test = Path_Min[j]; Path_test = treeData.Path[Nomer_test]; if(Path_test < MinimPath) {MinimPath = Path_test; Nomer_nmin = Nomer_test;} }//end of search_minimum

18 18 Умножение матриц (автор кода О. Нечаева, НГУ, лаборатория Intel) Перед началом вычислений вторую матрицу необходимо транспонировать – чтобы данные лежали в строке «подряд» - в C/C++ массивы располагаются по строкам Ускорение порядка 2 Делает возможным выигрыш от применения нижеследующего одновременный подсчет 4 элементов новой матрицы «размер строки кэша кратен объему подгружаемой информации», векторизация Ключи компиляции – сложные инструкции, оптимизация под Intel процессор Ускорение от сделанного – порядка 20 Конструкции OpenMP – Ускорение в 1.9 раза

19 19 Код умножения матриц #pragma omp parallel for private(j,k) for(int i=0;i<Size;i+=4) for(int j=0;j<128;j++) { for(int k=0;k<Size;k++) { C[i][j]+=A[i][k]*B[j][k]; C[i+1][j]+=A[i+1][k]*B[j][k]; C[i+2][j]+=A[i+2][k]*B[j][k]; C[i+3][j]+=A[i+3][k]*B[j][k]; }

20 20 Синтаксис конструкций OpenMP - продолжение

21 21 Параллельные регионы Параллельный регион – это структурированный блок кода, предназначенный для обработки множеством потоков Потоки включаются в работу там, где встретилась директива ‘parallel’ Все потоки, кроме главного, останавливают свою работу при выходе из параллельного региона Данные, описанные вне параллельной области, по умолчанию считаются общими («разделяемыми») для всех потоков, если нет специальных указаний («клауз» - private, firstprivate, lastprivate, threadprivate… #pragma omp parallel { блок кода } Перед тем, как выйти из параллельного региона, все потоки должны завершить свою работу, «дождаться друг друга»

22 22 Переменная окружения для числа потоков Для большинства систем # число потоков= #число процессоров Это справедливо для компиляторов Intel ® set OMP_NUM_THREADS=4 Для системы с одним процессором и гипертредингом число потоков необходимо задавать с помощью данной конструкции (по умолчанию будет 1 поток)

23 23 Параллелизм для цикла с целым параметром Два варианта кода #pragma omp parallel { #pragma omp for for (i=0;i< MAX; i++) res[i] = huge(); } #pragma omp parallel for for (i=0;i< MAX; i++) res[i] = huge(); Для переменной цикла i каждый поток «создает себе копию» - -т.е. когда поток №1 изменяет свою i.копия1, - -поток №2 об этом ничего не знает Потоки «делят» выполнение итераций цикла друг с другом, например: «1-ому – выполнение всех итераций до MAX/2, 2 –ому – все от MAX/2 – до конца»

24 24 Области видимости данных OpenMP использует модель общей (разделяемой - shared) памяти Большинство переменных считаются по умолчанию разделяемыми. Глобальные переменные являются общими (разделяемыми) для всех потоков

25 25 Области видимости данных Да, но не все разделяется... Локальные переменные в функциях, вызываемых из параллельного региона, являются частными (PRIVATE) Автоматические переменные, описанные в пределах параллельного блока, являются частными (PRIVATE) Номер итерации распараллеливаемого цикла является частным (private)

26 26 Атрибуты для изменения области видимости данных по умолчанию shared(varname,…) – переменные становятся разделяемыми private(varname,…)- переменные становятся частными

27 27 #pragma omp critical [(lock_name)] Определяет область «критического кода» в структурном блоке OpenMP*: критическая секция float RES; #pragma omp parallel { float B; #pragma omp for for(int i=0; i<niters; i++){ B = big_job(i); #pragma omp critical (RES_lock) consum (B, RES); } } Потоки стоят «в очереди» – только один может выполнять consum() - защита от «гонок данных» RES_lock - – условное обозначение защищаемого блока

28 28 OpenMP* «клауза» Reduction reduction (операция: список) Переменные в «списке» должны быть общими вне параллельного региона Внутри параллельного региона каждый поток создает свою копию каждой переменной в списке: PRIVATE –копия каждой переменной в «списке» создается каждым потоком и инициализируется в зависимости от типа «операции» Каждый поток независимо вычисляет результат операции для своей копии на своих данных Перед выходом из параллельного региона «операция» выполняется над всеми копиями всех потоков (например, сумма = сумма.поток1+сумма.поток2), и переменная снова становится «shared»

29 29 Значения, которыми инициализируются переменные в «списке», в зависимости от типа операции Операции C/C++ Reduction ОперацияЗначение +0 *1 -0 ^0 ОперацияЗначение &~0 |0 &&1 ||0

30 30 Распределение итераций между потоками «Клауза» schedule определяет, каким именно образом итерации цикла с целочисленным параметром должны быть поделены между потоками schedule(static [,chunk]) Блок итераций размером “chunk” выполняет один поток Когда все потоки все сделали свой “chunk”, друг друга подождали, опять также поделили – и т.д. schedule(dynamic[,chunk]) Блок итераций размером “chunk” выполняет один поток Неважно, что сделали другие, если поток сделал свой “chunk”, хватает следующую порцию schedule(guided[,chunk]) Режим захвата работы динамический, аналогично предыдущему Размер захватываемого блока непрерывно уменьшается, но не может быть меньше “chunk”

31 31 Schedule ClauseКогда применять STATIC Предсказуемая и одинаковая работа для итераций DYNAMIC Непредсказуемая, сильно неоднородное распределение работы между итерациями GUIDED Специальный вариант динамического распределения Условия, при которых выгоден режим

32 32 Параллельные секции Независимые участки кода могут выполняться параллельно Последовательный Параллельный #pragma omp parallel sections { #pragma omp section phase1(); #pragma omp section phase2(); #pragma omp section phase3(); }

33 33 Определяет блок кода, который может выполнять лишь один поток Выполняет код тот, кто приходит первый В конце «кода для одного» все потоки ждут друг друга Конструкция: код для одного потока #pragma omp parallel { DoManyThings(); #pragma omp single { ExchangeBoundaries(); } // threads wait here for single DoManyMoreThings(); }

34 34 Выделяет участок кода, который выполняет только главный поток В конце этого участка не подразумевается барьера – потоки «не ждут друг друга» Конструкция: код для «мастер - потока» #pragma omp parallel { DoManyThings(); #pragma omp master { //если не главный, выполняй //операторы ниже блока ExchangeBoundaries(); } DoManyMoreThings(); }

35 35 Барьеры Следующие конструкции подразумевают барьеры parallel for single Но барьер без необходимости понижает производительность Потоки ждут, вместо того, чтобы работать Убрать барьер можно с помощью клаузы nowait

36 36 Nowait Используется, когда потоки выполняют независимые вычисления #pragma single nowait { [...] } #pragma omp for nowait for(...) {...}; #pragma omp for schedule(dynamic,1) nowait for(int i=0; i<n; i++) a[i] = bigFunc1(i); #pragma omp for schedule(dynamic,1) for(int j=0; j<m; j++) b[j] = bigFunc2(j);

37 37 Барьер Применяется, если необходимо синхронизовать во времени работу потоков #pragma omp parallel shared (A, B, C) { DoSomeWork(A,B); printf(“Processed A into B\n”); #pragma omp barrier DoSomeWork(B,C); printf(“Processed B into C\n”); }

38 38 Atomic Специальный случай критической секции Применяется, если содержимое ячейки памяти изменяется достаточно простым образом #pragma omp parallel for shared(x, y, index, n) for (i = 0; i < n; i++) { #pragma omp atomic x[index[i]] += work1(i); y[i] += work2(i); }

39 39 OpenMP* API Получить номер потока int omp_get_thread_num(void); Определить количество потоков int omp_get_num_threads(void); Обычно не используются Получаемый код не преображается в последовательный Используется при отладке Необходим header file #include

40 40 OpenMP* - разновидности «private» FIRSTPRIVATE LASTPRIVATE THREADPRIVATE

41 41 Инициализация разделяемых переменных перед параллельной секцией Firstprivate incr=0; #pragma omp parallel for firstprivate(incr) for (I=0;I<=MAX;I++) { if ((I%2)==0) incr++; A(I)=incr; }

42 42 «update» разделяемых переменных после выхода из параллельной секции с последней итерации цикла Lastprivate void sq2(int n, double *lastterm) { double x; int i; #pragma omp parallel #pragma omp for lastprivate(x) for (i = 0; i < n; i++){ x = a[i]*a[i] + b[i]*b[i]; b[i] = sqrt(x); } lastterm = x; }

43 43 Инициализация из главного потока и копия каждому потоку Threadprivate struct Astruct A; #pragma omp threadprivate(A) … #pragma omp parallel copyin(A) do_something_to(&A); … #pragma omp parallel do_something_else_to(&A); Private copies of “A” persist between regions


Download ppt "Программирование в OpenMP ЛЕКЦИЯ №5 Калинина А.П.."

Similar presentations


Ads by Google