Слайд 1Средства разработки параллельных и распределенных программ
Судаков А.А.
“Параллельные и распределенные вычисления”
Лекция 19
Слайд 2План
Языки программирования
Средства отладки и профилирования
Оптимизация программ
Математические библиотеки
Стандартный интерфейс
операционных систем
Стандарт POSIX
Слайд 3Литература
Язык неявным параллелизмом Sisal http://www2.cmp.uea.ac.uk/~jrwg/Sisal/
Язык с поддержкой параллелизма erlang http://www.erlang.org/
Язык
с неявной поддержкой параллелизма pH http://www.csg.lcs.mit.edu/projects/languages/ph.shtml
Автораспараллеливающие компиляторы http://www.pgroup.com/
Adaptor http://www.scai.fraunhofer.de/EP-CACHE/adaptor/www/adaptor_home.html
Язык
программирования E http://www.erights.org/
Слайд 4Средства разработки
Языки программирования
Препроцессор
Компилятор или транслятор
Библиотеки (API)
Интерфейс (API) операционных систем
Средства отладки
программ
Отладчик
Средства проверки правильности кода
Средства повышения производительности
Оптимизация исполняемого кода
Профилирование
Слайд 5Поддержка параллелизма в языках программирования
Языки программирования
Без поддержки параллелизма
Язык программирования
не включает средства создания параллельных программ
С явной поддержкой параллелизма
В язык
программирования входят конструкции, которые позволяют разработчику указать критические разделы, общие переменные, топологию и т.д.
С неявной поддержкой параллелизма
В языке программирования нет явных конструкций, которые позволяют пользователю указать наличие параллельных участков, но есть определенные ограничения, которые позволяют коду выполняться на нескольких процессорах
Компиляторы с автораспараллеливанием
Для языка без поддержки параллелизма компилятор позволяет на основании последовательной программы сгенерировать параллельный код для того или другого типа машины
Слайд 6Языки без поддержки параллелизма
С, C++, Fortran, Pascal
Рассчитаны на создание
только последовательных программ
Возможность создания параллельный программ вводится с помощью вызовов
библиотечных функций или интерфейсов операционной системы
socket
Pthread
OpenMP
MPI
PVM
Большинство параллельных программ разрабатывается таким образом
Слайд 7Языки с явной поддержкой параллелизма
Расширения к «классическим» языкам программирования
К языку
программирования (Fortran, Pascal, C, C++) добавляется дополнительный набор инструкций для
явного указания участков, которые выполняются параллельно
mpC (multiprocessing C)
HPC (High Performance Fortran)
OpenMP
Языки с внутренней поддержкой параллельных конструкций
Java
erlang
Слайд 8Языки с неявной поддержкой параллелизма
Язык не имеет специальных конструкций для
указания участков параллельного выполнения
Синтаксис языка имеет специфический вид для облегчения
автораспараллеливания
Транслятор или компилятор сам выполняет распараллеливание кода
Sisal
pH
Слайд 9Компиляторы с автораспараллеливанием
На основе последовательной программы на языке без поддержки
параллелизма создает параллельный код
Portland group – автораспараллеливание (С, С++, Fortran)
Absoft
– препроцессор Fortran для вставки библиотечный вызовов с обменом сообщениями
Adaptor – препроцессор для автораспараллеливания
Слайд 10Языки для создания распределнных программ
Без поддержки распределенного программирования
Через библиотечные
вызовы
С явной поддержкой распределнности
Специальные конструкции для работы с удаленными
объектами
E
SR
CORBA IDL
Слайд 11Средства отладки
Отладчики кода
Gdb, idb,
Почти все поддерживают многопоточность
Для распределенных программ
необходимо запускать на нескольких машинах
Проверка кода
Позволяют установить возможные проблемы
Deadlock
Race
Intel thread
checker
Слайд 12Средства оптимизации
Профилировщики
Сбор информации о процессе выполнения программы
Время выполнения каждой функции
Частота
обращения к данным
Определение самых проблемных участков
Gprof
Net wampir – профилировщик для
MPI программ
Оптимизаторы кода
Компиляторы с оптимизацией исполняемого кода
Оптимизаторы исходного кода
adaptor
Слайд 13Параллельные математические библиотеки
BLAS – basic linear algebra software
ATLAS – auto-tuning
linear algebra software
SCALAPACK – параллельные библиотеки линейной алгебры
MKL – оптимизированные
библиотеки для intel
Слайд 14Интерфейс операционных систем
Стандарт POSIX – portable operation system interface
Функции создания
и работы с процессами
Функции работы с потоками
Функции работы с файлами
Функции
работы с общей памятью
Функции взаимодействия по сети
Функции включены в стандартную библиотеку функций libc
Слайд 15Работа с процессами
Создание процессов
int fork() – создание копии программы
Для родительского
процесса возвращается номер порожденного процесса
Для порожденного процесса возвращается 0
Выполнение
программ
int execlp(const char *file, const char *arg, ...)
выполнение другой программы в контексте текущего процесса
Функция не возвращается, если не произошло ошибки
Слайд 16Пример fork
// fork.c
#include
#include
int main() {
int child = 0;
//до этого места
была одна программа
switch ( child = fork() ){
// две копии одной программы
case 0: //порожденный процесс попадает сюда
printf("I am child\n");
break;
default: //родительскийпроцесс попадает сюда
printf("I am parent, child pid=%d\n",child);
break;
}
//здесь работают обе программы
return 0;
}
Слайд 17Пример fork.c
[saa@cluster processes]$ gcc ./fork.c
[saa@cluster processes]$ ./a.out
I am parent, child
pid=26083
I am child
[saa@cluster processes]$
Слайд 18Пример Exec
// exec.c
#include
#include
int main() {
int child = 0;
//до этого места
была одна программа
switch ( child = fork() ){
// две копии одной программы
case 0: //порожденный процесс попадает сюда
printf("I am child , executing ps\n");
execlp("ps","ps", NULL);
break;
default: //родительскийпроцесс попадает сюда
printf("I am parent, child pid=%d\n",child);
break;
}
//здесь работают обе программы
return 0;
}
Слайд 19Пример exec
[saa@cluster processes]$ gcc ./exec.c
[saa@cluster processes]$ ./a.out
I am parent, child
pid=26206
I am child, executing ps
[saa@cluster processes]$
PID TTY
TIME CMD
20979 pts/9 00:00:00 bash
26118 pts/9 00:00:00 vim
26206 pts/9 00:00:00 ps
Слайд 20Наследование открытых файлов
После вызова fork() порожденный процесс по умолчанию наследует
открытые родителем файлы
После вызова exec() новая программа наследует открытые файлы
Возможность
перенаправления ввода/вывода
Слайд 21Файловые операции
Стандарт POSIX – дескриптор файла – целочисленный номер
int open(const
char *pathname, int flags);
int close(int fd);
ssize_t read(int fd, void
*buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
Стандарт ANSI C – дескриптор файла – указатель на структуру
FILE *fopen(const char *path, const char *mode);
int fclose(FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
Слайд 22Файловые операции
Файловые операции возможны с любыми файловыми объектами
Дисковый файл
Файл устройства
Конвейер
(fifo)
Сокет
Каждая программа обычно имеет в начале 3 дескриптора
Стандартный ввод дескриптор
номер 0 - входной
Стандартный вывод дескриптор номер 1 - выходной
Стандартный поток ошибок дескриптор номер 2 -выходной
Слайд 23Переназначение файлового дескриптора
Файловый дескриптор соответствует открытому файлу
Можно менять номера дескрипторов
файлов, чтобы связывать нужный файл с нужным дескриптором
Функции
int dup(int
oldfd); - создать новый дескриптор – копию старого
int dup2(int oldfd, int newfd); - сделать так, чтобы newfd стал тоже связан с файлом, с которым связан oldfd
Слайд 24Пример перенаправления ввода вывода
//io.c
#include
#include
#include
#include
int main() {
int out_fd;
//открываем новый
файл
out_fd = open("./new_file",O_WRONLY|O_CREAT);
//делаем это файл новым стандартным вводом
dup2(out_fd,1);
//выполненная команда выдаст результат в новый файл
//учитывая наследование дескрипторов открытых файлов
execlp("ps","ps",NULL);
}
Слайд 25Пример выполнения
[saa@cluster processes]$ gcc io.c
[saa@cluster processes]$ ./a.out
[saa@cluster processes]$ cat new_file
PID TTY TIME CMD
26544 pts/1
00:00:00 bash
27315 pts/1 00:00:00 ps
[saa@cluster processes]$
Слайд 26Взаимодействие между процессами
Конвейеры
Общая память
Семафоры
Слайд 27Конвейеры
int pipe(int filedes[2]);
Создает массив из двух связанных дескрипторов
Все, что записывается
в одни дескриптор, можно читать из другого
Используется для перенаправление ввода-вывода
между родительским и порожденным процессами
Слайд 28Пример
#include
#include
int main() {
int channel[2];
pipe(channel);
char buf[10];
switch ( fork() ){
case 0: //порожденный процесс попадает сюда
//мы только пишем
close(channel[0]);
// пишем родителю
write(channel[1],"MESSAGE",8);
break;
default: //родительскийпроцесс попадает сюда
// мы только ситаем
close(channel[1]);
// читаем информацию от порожденного
read(channel[0],buf,8);
printf("GOT FROM CHILD \"%s\"\n", buf);
break;
}
return 0;
}
Слайд 29Пример выполнения
[saa@cluster processes]$ gcc ./pipe.c
[saa@cluster processes]$ ./a.out
GOT FROM CHILD "MESSAGE"
Слайд 30Общая память
Есть два стандарта UNIX и POSIX
Стандарт POSIX
Общая память –
файловый объект
Операции
Создать
Открыть
Задать размер
Уничтожить
Отобразить на память процесса
Удалить отображение на адресное
пространство
Слайд 31Функции работы с общей памятью
Создать или открыть область памяти
int shm_open(const
char *name, int oflag, mode_t mode);
Задать размер области (как файла)
ftruncate()
или write()
Удалить область памяти
int shm_unlink(const char *name);
Закрыть область памяти
int close(int)
Отобразить на адресное пространство процесса
void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
Удалить отображение
int munmap(void *start, size_t length);
Слайд 32Пример работы с общей памятью
#include
#include
#include
#include
#include
#include
int main(){
int mem_fd;
char* shm;
//создаем область общей памяти
mem_fd = shm_open("/test.mem",O_RDWR|O_CREAT, S_IRWXU);
shm_unlink("/test.mem");
ftruncate(mem_fd,100); //задаем размер в 100 байт
switch(fork()){
case 0: //child
// отображаем общую область пямяти в адресное пространство
shm = mmap(NULL, 100, PROT_WRITE , MAP_SHARED, mem_fd, 0);
// записываем информацию в общую область памяти
sprintf(shm,"MESSAGE FROM CHILD");
break;
default: //parent
sleep(1); // ждем одну секунду
//отображаем общую область пямяти в адресное пространство
shm = mmap(NULL, 100, PROT_READ , MAP_SHARED, mem_fd, 0);
// читаем информацию из общей области памяти
printf("Read from child=\"%s\"\n",shm);
break;
}
// отсоединяем и удаляем общую область памяти
close(mem_fd);
munmap(shm,100);
return 0;
}
Слайд 33Пример выполнения
saa@cluster processes]$ gcc shm_posix.c -lrt
[saa@cluster processes]$ ./a.out
Read from child="MESSAGE
FROM CHILD"
Слайд 34Семафоры
Семафор – взаимоисключающая переменная
Есть два стандарта UNIX и POSIX
Стандарт UNIX
Семафоры
создаются специальными системными вызовами
Операции
создать
down – захватить (опустить, уменьшить на 1)
up
– вернуть (поднять, увеличить на 1)
удалить
Слайд 35Функции работы с семафорами
Создать семафор
int semget(key_t key, int nsems, int
semflg);
Операции с семафорами
int semop(int semid, struct sembuf *sops, unsigned nsops);
Управление
семафорами
int semctl(int semid, int semnum, int cmd, ...);
Слайд 36Операции с семафорами
Операция представляется в виде структуры
Struct sembuf {
unsigned short sem_num; /* номер семафора */
short sem_op;
/* операция */
short sem_flg; /* флаги */
}
Операция
Увеличение на sem_op (sem_op > 0)
Уменьшение на sem_op (sem_op < 0)
Слайд 37Пример программы работы c общей памятью и семафором
#include
#include
#include
#include
#include
#include
#include
#include
int main(){
int mem_fd;
char* shm;
int sem; //дескриптор семафора
struct sembuf up = {0,1,1}; //команда поднять семафор
struct sembuf down = {0,-1,1}; //команда опустить семафор
mem_fd = shm_open("/test.mem",O_RDWR|O_CREAT, S_IRWXU);
shm_unlink("/test.mem");
ftruncate(mem_fd,100);
shm = mmap(NULL, 100, PROT_WRITE|PROT_READ , MAP_SHARED, mem_fd, 0);
sem=semget(IPC_PRIVATE,1,S_IRUSR|S_IWUSR|IPC_CREAT); //создаем семафор
semop(sem,&down,0); //опускаем семафор
switch(fork()){
case 0: //child
sprintf(shm,"MESSAGE FROM CHILD");
semop(sem,&up,1); // разрешем читать
break;
default: //parent
semop(sem,&down,1); // ждем разрешения читать
printf("Read from child=\"%s\"\n",shm);
semctl(sem,0,IPC_RMID,0); // удаляем семафор
break;
}
close(mem_fd); munmap(shm,100); // отсоединяем и удаляем общую область памяти
return 0;
}