Слайд 2
Москва, 2012 г.
Технология параллельного программирования OpenMP : Функциональная
отладка OpenMP-программ
Содержание
Трудно обнаруживаемые ошибки типа race condition (конфликт
доступа к данным).
Ошибки типа deadlock (взаимная блокировка нитей).
Ошибки, связанные с использованием неинициализированных переменных.
Автоматизированный поиск ошибок в OpenMP-программах при помощи Intel Thread Checker (Intel Parallel Inspector) и Sun Studio Thread Analyzer (Oracle Solaris Studio).
Слайд 3
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
Результат зависит от порядка
выполнения команд. Требуется взаимное исключение критических интервалов.
При взаимодействии через общую память нити должны синхронизовать свое выполнение.
#pragma omp parallel
{
sum = sum + val;
}
Слайд 4
Ошибка возникает при одновременном выполнении следующих условий:
Две или
более нитей обращаются к одной и той же ячейке
памяти.
По крайней мере, один из этих доступов к памяти является записью.
Нити не синхронизируют свой доступ к данной ячейки памяти.
При одновременном выполнении всех трех условий порядок доступа становится неопределенным.
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
Слайд 5
Использование различных компиляторов (различных опций оптимизации, включение/отключение режима
отладки при компиляции программы), применение различных стратегий планирования выполнения
нитей в различных ОС, может приводить к тому, что в каких-то условиях (например, на одной вычислительной машине) ошибка не будет проявляться, а в других (на другой машине) – приводить к некорректной работе программы.
От запуска к запуску программа может выдавать различные результаты в зависимости от порядка доступа.
Отловить такую ошибку очень тяжело.
Причиной таких ошибок, как правило являются:
неверное определение класса переменной,
отсутствие синхронизации.
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
Слайд 6
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
#define N
float a[N], tmp;
#pragma
omp parallel
{
#pragma omp for
for(int i=0; i tmp= a[i]*a[i];
a[i]=1-tmp;
}
}
Слайд 7
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
#define N
float a[N], tmp;
#pragma
omp parallel
{
#pragma omp for
for(int i=0; i
tmp= a[i]*a[i];
a[i]=1-tmp;
}
}
#define N
float a[N], tmp;
#pragma omp parallel
{
#pragma omp for private(tmp)
for(int i=0; i tmp= a[i]*a[i];
a[i]=1-tmp;
}
}
Слайд 8
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
file1.c
int counter = 0;
#pragma
omp threadprivate(counter)
int increment_counter()
{
counter++;
return(counter);
}
file2.c
extern int counter;
int decrement_counter()
{
counter--;
return(counter);
}
Слайд 9
Директива threadprivate
threadprivate – переменные сохраняют
глобальную область видимости внутри каждой нити
#pragma omp threadprivate (Var)
END
PARALLEL
PARALLEL
END PARALLEL
PARALLEL
Var = 1
Var = 2
… = Var
… = Var
Если количество нитей не изменилось, то каждая нить получит значение, посчитанное в предыдущей параллельной области.
Технология параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
Москва, 2012 г.
Слайд 10
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
file1.c
int counter = 0;
#pragma
omp threadprivate(counter)
int increment_counter()
{
counter++;
return(counter);
}
file2.c
extern int counter;
#pragma omp threadprivate(counter)
int decrement_counter()
{
counter--;
return(counter);
}
Слайд 11
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
#define N 100
#define Max(a,b)
((a)>(b)?(a):(b))
float A[N], maxval;
#pragma omp parallel
{
#pragma omp master
maxval = 0.0;
#pragma omp for
for(int i=0; i maxval = Max(A[i],maxval);
}
}
Слайд 12
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
#define N 100
#define Max(a,b)
((a)>(b)?(a):(b))
float A[N], maxval;
#pragma omp parallel
{
#pragma omp master
maxval = 0.0;
#pragma omp for
for(int i=0; i
maxval = Max(A[i],maxval);
}
}
#define N 100
#define Max(a,b) ((a)>(b)?(a):(b))
float A[N], maxval;
#pragma omp parallel
{
#pragma omp master
maxval = 0.0;
#pragma omp for
for(int i=0; i #pragma omp critical
maxval = Max(A[i],maxval);
}
}
Слайд 13
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
#define N 100
#define Max(a,b)
((a)>(b)?(a):(b))
float A[N], maxval;
#pragma omp parallel
{
#pragma omp master
maxval = 0.0;
#pragma omp for
for(int i=0; i
maxval = Max(A[i],maxval);
}
}
#define N 100
#define Max(a,b) ((a)>(b)?(a):(b))
float A[N], maxval;
#pragma omp parallel
{
#pragma omp master
maxval = 0.0;
#pragma omp barrier
#pragma omp for
for(int i=0; i #pragma omp critical
maxval = Max(A[i],maxval);
}
}
Слайд 14
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
void example(int n, int
m, float *a, float *b, float *с, float *z)
{
int i;
float sum = 0.0;
#pragma omp parallel
{
#pragma omp for schedule(runtime) nowait
for (i=0; i c[i] = (a[i] + b[i]) / 2.0;
}
#pragma omp for schedule(runtime) nowait
for (i=0; i z[i] = sqrt(c[i]);
}
}
Слайд 15
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
void example(int n, int
m, float *a, float *b, float *с, float *z)
{
int i;
float sum = 0.0;
#pragma omp parallel
{
#pragma omp for schedule(runtime)
for (i=0; i c[i] = (a[i] + b[i]) / 2.0;
}
#pragma omp for schedule(runtime) nowait
for (i=0; i z[i] = sqrt(c[i]);
}
}
Слайд 16
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
void example(int n, float
*a, float *b, float *с, float *z)
{
int i;
float sum = 0.0;
#pragma omp parallel
{
#pragma omp for nowait reduction (+: sum)
for (i=0; i c[i] = (a[i] + b[i]) / 2.0;
sum += c[i];
}
#pragma omp for nowait
for (i=0; i z[i] = sqrt(b[i]);
#pragma omp master
printf (“Sum of array C=%g\n”,sum);
}
}
Слайд 17
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
void example(int n, float
*a, float *b, float *с, float *z)
{
int i;
float sum = 0.0;
#pragma omp parallel
{
#pragma omp for schedule(static) nowait reduction (+: sum)
for (i=0; i c[i] = (a[i] + b[i]) / 2.0;
sum += c[i];
}
#pragma omp for schedule(static) nowait
for (i=0; i z[i] = sqrt(b[i]);
#pragma omp barrier
#pragma omp master
printf (“Sum of array C=%g\n”,sum);
}
}
Слайд 18
Распределение циклов с зависимостью по данным. Организация конвейерного
выполнения цикла.
for(int i = 1; i
N; i++)
for(int j = 1; j < N; j++)
a[i][j] = (a[i-1][j] + a[i][j-1] + a[i+1][j] + a[i][j+1]) / 4
Технология параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
Москва, 2012 г.
Слайд 19
Распределение циклов с зависимостью по данным. Организация конвейерного
выполнения цикла.
Технология параллельного программирования OpenMP : Функциональная отладка
OpenMP-программ
Москва, 2012 г.
Слайд 20
001
Модель памяти в OpenMP
Нить
Кэш общих переменных
Общая память
Private-переменные
Threadprivate-переменные
001
Нить
Кэш общих переменных
Private-переменные
Threadprivate-переменные
001
Нить
Кэш общих
переменных
Private-переменные
Threadprivate-переменные
Технология параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
Москва, 2012 г.
Слайд 21
001
Нить 0
Общая память
001
Нить 1
static int i =
0;
… = i + 1;
i = i + 1;
i
= 0
i = 1
… = i + 2; // ?
#pragma omp flush (i)
#pragma omp flush (i)
i = 1
i = 1
Модель памяти в OpenMP
Технология параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
Москва, 2012 г.
Слайд 22
Консистентность памяти в OpenMP
Корректная последовательность работы нитей с
переменной:
Нить0 записывает значение переменной - write(var)
Нить0 выполняет операцию синхронизации
– flush (var)
Нить1 выполняет операцию синхронизации – flush (var)
Нить1 читает значение переменной – read (var)
Директива flush:
#pragma omp flush [(список переменных)] - для Си
По умолчанию все переменные приводятся в консистентное состояние (#pragma omp flush):
При барьерной синхронизации.
При входе и выходе из конструкций parallel, critical и ordered.
При выходе из конструкций распределения работ (for, single, sections, workshare), если не указана клауза nowait.
При вызове omp_set_lock и omp_unset_lock.
При вызове omp_test_lock, omp_set_nest_lock, omp_unset_nest_lock и omp_test_nest_lock, если изменилось состояние семафора.
Технология параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
Москва, 2012 г.
Слайд 23
Распределение циклов с зависимостью по данным. Организация конвейерного
выполнения цикла.
Технология параллельного программирования OpenMP : Функциональная отладка
OpenMP-программ
Москва, 2012 г.
Слайд 24
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
#define ITMAX 20
#define Max(a,b)
((a)>(b)?(a):(b))
double MAXEPS = 0.5;
double grid[L][L], tmp[L][L],eps;
#pragma omp parallel
{
for (int it=0;it #pragma omp single
eps= 0.;
#pragma omp for
for (int i=1; i for (int j=1; j #pragma omp critical
eps = Max(fabs(tmp[i][j]-grid[i][j]),eps);
grid[i][j] = tmp[i][j];
}
#pragma omp for
for (int i=1; i for (int j=1; j tmp[i][j] = 0.25 * ( grid[i-1][j] + grid[i+1][j] + grid[i][j-1] + grid[i][j+1]);
if (eps < MAXEPS) break;
}
}
Слайд 25
Конфликт доступа к данным
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
#define Max(a,b) ((a)>(b)?(a):(b))
double MAXEPS
= 0.5;
double grid[L][L], tmp[L][L],eps;
#pragma omp parallel
{
for (int it=0;it #pragma omp barrier
#pragma omp single
eps= 0.;
#pragma omp for
for (int i=1; i for (int j=1; j #pragma omp critical
eps = Max(fabs(tmp[i][j]-grid[i][j]),eps);
grid[i][j] = tmp[i][j];
}
#pragma omp for
for (int i=1; i for (int j=1; j tmp[i][j] = 0.25 * ( grid[i-1][j] + grid[i+1][j] + grid[i][j-1] + grid[i][j+1]);
if (eps < MAXEPS) break;
}
}
Слайд 26
Взаимная блокировка нитей
Москва, 2012 г.
Технология параллельного программирования OpenMP
: Функциональная отладка OpenMP-программ
#define N 10
int A[N],B[N], sum;
#pragma
omp parallel num_threads(10)
{
int iam=omp_get_thread_num();
if (iam ==0) {
#pragma omp critical (update_a)
#pragma omp critical (update_b)
sum +=A[iam];
} else {
#pragma omp critical (update_b)
#pragma omp critical (update_a)
sum +=B[iam];
}
}
Слайд 27
Семафоры в OpenMP
Москва, 2012 г.
Технология параллельного программирования OpenMP
: Функциональная отладка OpenMP-программ
#include
#define N 100
#define Max(a,b)
((a)>(b)?(a):(b))
int main ()
{
omp_lock_t lck;
float A[N], maxval;
#pragma omp parallel
{
#pragma omp master
maxval = 0.0;
#pragma omp barrier
#pragma omp for
for(int i=0; i omp_set_lock(&lck);
maxval = Max(A[i],maxval);
omp_unset_lock(&lck);
}
}
return 0;
}
Слайд 28
Семафоры в OpenMP
Москва, 2012 г.
Технология параллельного программирования OpenMP
: Функциональная отладка OpenMP-программ
#include
#define N 100
#define Max(a,b)
((a)>(b)?(a):(b))
int main ()
{
omp_lock_t lck;
float A[N], maxval;
omp_init_lock(&lck);
#pragma omp parallel
{
#pragma omp master
maxval = 0.0;
#pragma omp barrier
#pragma omp for
for(int i=0; i omp_set_lock(&lck);
maxval = Max(A[i],maxval);
omp_unset_lock(&lck);
}
}
omp_destroy_lock(&lck);
return 0;
}
Слайд 29
Взаимная блокировка нитей
Москва, 2012 г.
Технология параллельного программирования OpenMP
: Функциональная отладка OpenMP-программ
#pragma omp parallel
{
int iam=omp_get_thread_num();
if (iam ==0) {
omp_set_lock (&lcka);
omp_set_lock (&lckb);
x = x + 1;
omp_unset_lock (&lckb);
omp_unset_lock (&lcka);
} else {
omp_set_lock (&lckb);
omp_set_lock (&lcka);
x = x + 2;
omp_unset_lock (&lcka);
omp_unset_lock (&lckb);
}
}
Слайд 30
Взаимная блокировка нитей
Москва, 2012 г.
Технология параллельного программирования OpenMP
: Функциональная отладка OpenMP-программ
#pragma omp parallel
{
int iam=omp_get_thread_num();
if (iam ==0) {
omp_set_lock (&lcka);
while (x<0); /*цикл ожидания*/
omp_unset_lock (&lcka);
} else {
omp_set_lock (&lcka);
x++;
omp_unset_lock (&lcka);
}
}
}
Слайд 31
Неинициализированные переменные
Москва, 2012 г.
Технология параллельного программирования OpenMP :
Функциональная отладка OpenMP-программ
#define N 100
#define Max(a,b) ((a)>(b)?(a):(b))
float A[N],
maxval, localmaxval;
maxval = localmaxval = 0.0;
#pragma omp parallel private (localmaxval)
{
#pragma omp for
for(int i=0; i localmaxval = Max(A[i],localmaxval);
}
#pragma omp critical
maxval = Max(localmaxval,maxval);
}
Слайд 32
Неинициализированные переменные
Москва, 2012 г.
Технология параллельного программирования OpenMP :
Функциональная отладка OpenMP-программ
#define N 100
#define Max(a,b) ((a)>(b)?(a):(b))
float A[N],
maxval, localmaxval;
maxval = localmaxval = 0.0;
#pragma omp parallel firstprivate (localmaxval)
{
#pragma omp for
for(int i=0; i localmaxval = Max(A[i],localmaxval);
}
#pragma omp critical
maxval = Max(localmaxval,maxval);
}
Слайд 33
Неинициализированные переменные
Москва, 2012 г.
Технология параллельного программирования OpenMP :
Функциональная отладка OpenMP-программ
int tmp = 0;
#pragma omp parallel
{
#pragma
omp for firstprivate(tmp), lastprivate (tmp)
for (int j = 0; j < 100; ++j) {
if (j<98) tmp = j;
}
printf(“%d\n”, tmp);
}
Слайд 34
Неинициализированные переменные
Москва, 2012 г.
Технология параллельного программирования OpenMP :
Функциональная отладка OpenMP-программ
static int counter;
#pragma omp threadprivate(counter)
int main
() {
counter = 0;
#pragma omp parallel
{
counter++;
}
}
Слайд 35
Неинициализированные переменные
Москва, 2012 г.
Технология параллельного программирования OpenMP :
Функциональная отладка OpenMP-программ
static int counter;
#pragma omp threadprivate(counter)
int main
() {
counter = 0;
#pragma omp parallel copyin (counter)
{
counter++;
}
}
Слайд 36
Автоматизированный поиск ошибок. Intel Thread Checker (Intel Parallel
Inspector)
Москва, 2012 г.
Технология параллельного программирования OpenMP : Функциональная отладка
OpenMP-программ
KAI Assure for Threads (Kuck and Associates)
Анализ программы основан на процедуре инструментации.
Инструментация – вставка обращений для записи действий, потенциально способных привести к ошибкам: работа с памятью, вызовы операций синхронизации и работа с потоками.
Может выполняться:
автоматически (бинарная инструментация) на уровне исполняемого модуля (а также dll-библиотеки)
и/или по указанию программиста на уровне исходного кода (компиляторная инструментация Windows).
Слайд 37
Автоматизированный поиск ошибок. Intel Thread Checker
Москва, 2012 г.
Технология
параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
Для каждой
использованной в программе переменной сохраняется:
адрес переменной;
тип использования (read или write);
наличие/отсутствие операции синхронизации;
номер строки и имя файла;
call stack.
Инструментация программы + большой объем сохраняемой информации для каждого обращения = существенные накладные расходы и замедление выполнения программы.
Слайд 38
Пакет тестов SPLASH-2 (Stanford Parallel Applications for Shared
Memory) на 4-х ядерной машине
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ
http://iacoma.cs.uiuc.edu/iacoma-papers/asid06.pdf
Слайд 39
Автоматизированный поиск ошибок. Sun Thread Analyzer
Москва, 2012 г.
Технология
параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
Инструментация программы:
cc
-xinstrument=datarace -g -xopenmp=noopt test.c
Накопление информации о программе:
еxport OMP_NUM_THREADS=2
collect -r race ./a.out
collect -r deadlock ./a.out
collect -r all ./a.out
Получение результатов анализа программы
tha test.1.er => GUI
er_print test.1.er => интерфейс командной строки
Слайд 40
Автоматизированный поиск ошибок. Sun Thread Analyzer
Москва, 2012 г.
Технология
параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
if (iam==0)
{
user_lock ();
data = …
…
} else {
user_lock ();
… = data;
…
}
if (iam==0) {
ptr1 = mymalloc(sizeof(data_t));
ptr1->data = ...
...
myfree(ptr1);
} else {
ptr2 = mymalloc(sizeof(data_t));
ptr2->data = ...
...
myfree(ptr2);
}
Может выдавать сообщения об ошибках там где их нет
Слайд 41
Intel Thread Checker и Sun Thread Analyzer
Москва, 2012
г.
Технология параллельного программирования OpenMP : Функциональная отладка OpenMP-программ
http://www.fz-juelich.de/nic-series/volume38/terboven.pdf
Слайд 47
Спасибо за внимание!
Вопросы?
Москва, 2012 г.
Технология параллельного программирования OpenMP
: Функциональная отладка OpenMP-программ
Слайд 48
Отладка эффективности OpenMP-программ.
Следующая тема
Москва, 2012 г.
Технология параллельного программирования
OpenMP : Функциональная отладка OpenMP-программ