Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

LEC02

.pdf
Скачиваний:
15
Добавлен:
14.04.2015
Размер:
237.57 Кб
Скачать

Сравнение с законом Амдала

Пусть N = 100, M = 20, α = 0.05

Параллельное ускорение

7

6

5

4

S по Бухановскому

3

S по Амдалу

2

 

 

 

 

 

Предел

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

0

1

6

11

16

21

26

31

Количество вычислителей (потоков)

11

Введение в OpenMP

1. Подключить заголовок #include <omp.h>

Этот заголовочный файл нужен, только если будут использоваться функции с префиксом “omp_” (без которых вполне можно обойтись в параллельной программе). Если эти функции используются, программа теряет свойство прямой совместимости.

2. Использовать для компилятора ключ «–fopenmp».

Указанный вид опция имеет в gcc.

Для других компиляторов опция имеет другой вид:

Компилятор

Вид опции

 

 

gcc

-fopenmp

 

 

icc (Intel C/C++ compiler)

-openmp

 

 

Sun C/C++ compiler

-xopenmp

 

 

Visual Studio C/C++ compiler

/openmp

 

 

PGI (Nvidia C/C++ compiler)

-mp

 

 

12

Директива “omp parallel”

#pragma omp parallel printf(“Hello, OpenMP!\n”);

При запуске на трёхъядерном процессоре:

Hello, OpenMP!

Hello, OpenMP!

Hello, OpenMP!

При запуске на одноядерном процессоре:

Hello, OpenMP!

Если программист не указал количество потоков, которое должен создать OpenMP, то по умолчанию создаётся количество потоков, равное количеству логических процессоров на ЭВМ.

13

Параметр num_threads(k)

#pragma omp parallel num_threads(8)

printf("Hello, OpenMP (thread #%u)\n", omp_get_thread_num());

При запуске на n-ядерном процессоре (n – любое):

Hello, OpenMP (thread #0)

Hello, OpenMP (thread #7)

Hello, OpenMP (thread #4)

Hello, OpenMP (thread #5)

Hello, OpenMP (thread #6)

Hello, OpenMP (thread #1)

Hello, OpenMP (thread #2)

Hello, OpenMP (thread #3)

• Порядок выполнения кода потоками непредсказуем.

• Потоки (треды, threads) нумеруются с нуля.

• Поток номер 0 называют мастер-потоком (master thread).

• При вызове функции omp_get_thread_num в однопоточном режим,

она всегда возвращает 0 (т.е. номер мастер-потока).

14

Функция omp_get_thread_num

Последовательная программа

Распараллеленная программа

sort_matrix(A);

#pragma omp parallel num_threads(2)

transpose_matrix(B);

if (omp_get_thread_num(0) == 0)

 

sort_matrix(A);

 

else

 

transpose_matrix(B);

OpenMP создаст два потока (треда), один из которых будет сортировать матрицу_А (матер-поток), а другой в это же самое время параллельно будет транспонировать матрицу_В (поток с номером 1). Распараллеливание происходит без конфликтов, т.к. эти две операции никак не влияют друг на друга.

Пример, когда распараллеливание невозможно (вторую операцию невозможно выполнить, пока не выполнена первая):

sort_matrix(A, lines, columns); transpose_matrix(A, lines, columns);

15

Параметр sections

Последовательная программа

Распараллеленная программа

sort_matrix(A);

#pragma omp parallel sections {

transpose_matrix(B);

#pragma omp section

 

sort_matrix(A);

 

#pragma omp section

 

transpose_matrix(B);

 

}

OpenMP создаст два потока (треда), один из которых будет сортировать матрицу_А, а другой в это же самое время параллельно будет транспонировать матрицу_В.

Это решение аналогично предыдущему, за исключением того, что невозможно сказать, какой из потоков (0 или 1) будет выполнять сортировку, а какой – транспонирование.

Количество создаваемыйх потоков можно увеличить простым добавлением секций #pragma omp section.

16

Канонический цикл for

Цикл for называется каноническим, если можно на этапе компиляции рассчитать количество итераций (независимо от входных данных). Это возможно, если одновременно выполняются следующие условия:

внутри цикла нет операций break;

внутри цикла нет операции goto, ведущей вовне цикла;

переменная цикла (итератор) не изменяется внутри цикла;

запись цикла имеет вид:

17

#pragma omp for

Итерации внутри канонических циклов for можно поделить между несколькими потоками для параллельного исполнения, указав всего одну директиву:

#pragma omp parallel for num_threads(2) private(i) shared(a, b) for(i = 0; i < 20; i++) a[i] = i + b;

Поток 0 заполнит элементы c a[0] по a[9]. Поток 1 заполнит элементы c a[10] по a[19]. ОpenMP создаёт локальную копию переменной i для каждого потока (поэтому при выполнении i++ потоки не мешают друг другу). Переменные a и b являются общими для потоков (что не является проблемой, т.к. внутри цикла обе используются только для чтения и не изменяются).

Если цикл не является каноническим, OpenMP либо не будет

его распараллеливать, либо распараллелит с ошибками.

18

Область видимости по умолчанию

Переменная-итератор по умолчанию считается private, все остальные переменные по умолчанию считаются shared, поэтому иногда можно не указывать область видимости переменных.

Пример 1 (по умолчанию: i – private; x и N – shared) #pragma omp parallel for

for(i = 0; i < N; i++) {

a[i] = sqrt(sin(x)+cos(x)/ln(x));

}

Пример 2 (по умолчанию j и k считались бы shared, что ошибочно) #pragma omp parallel for private(j,k)

for(i = 2; i <= N-1; i++) for(j = 2; j <= i; j++)

for(k = 1; k <= M; k++)

b[i][j] += a[i-1][j]/k + a[i+1][j]/k;

}

19

#pragma omp for: конфликты

Если итерация k влияет на результаты итерации m, то цикл нельзя распараллеливать, т.к. нельзя заранее предсказать порядок завершения итераций несколькими потоками. Ответственность за обнаружение таких конфликтов лежит на программисте.

OpenMP не обнаружит взаимозависимость итераций и скомпилирует следующую ошибочную программу:

#pragma omp parallel for num_threads(2) for(i = 1; i < 20; i++) a[i] = 2*a[i – 1];

Поток 0 не успеет заполнить элемент a[9] к тому моменту, когда поток 1 будет вычислять значение a[10] = 2*a[9].

20