- •Лабораторные работы по курсу «Параллельное программирование»
- •Кластер Beowulf
- •Структура кластера кафедры 304
- •Организация взаимодействия между процессами при параллельных вычислениях
- •Основные функции mpi
- •Вычисление числа π методом численного интегрирования
- •Вычисление числа π методом Монте-Карло
- •Введение
- •Коммуникации точка-точка в mpi
- •Содержание отчета
- •Лабораторная работа №2
- •Коллективные коммуникации в mpi
- •Алгоритмы параллельного поиска и сортировки
- •Задание
- •Содержание отчета
- •Лабораторная работа №3
- •Введение
- •Умножение матриц ленточным методом
- •Алгоритм Фокса умножения матриц
- •Пример работы Fox's алгоритма
- •Этап 0 (шаг 1 ( слева ), шаг 2 ( по центру ), шаг 3 ( справа ) ):
- •Этап 1 ( слева ) и этап 2 (справа ):
- •Содержание отчета
- •Список литературы
Содержание отчета
Постановка задачи, вариант.
Текст параллельной программы на языке С согласно заданию.
Результаты запуска программы на одном узле, время выполнения ti, результат вычислений, ошибка.
Результаты запуска программы на сервере, время выполнения, результат вычислений, ошибка.
Описать параллельный алгоритм, информационные потоки при выполнении программы и загрузку КЭШ-памяти узлов. Вычислить по результатам работы программы коэффициент Амдала - Кj.
Учитывая результаты работы группы студентов, построить гистограмму зависимости Кj , ti от количества процессоров участвующих в вычислениях.
Выводы. Рекомендации по улучшению быстродействия программы.
Лабораторная работа №2
“ Программирование с использованием параллельной библиотеки MPI ”
Цель работы – обучение программированию с использованием параллельной библиотеки MPI , закрепление навыков работы с функциями передачи сообщений.
Введение
Обработка больших объемов данных всегда требует больших вычислительных ресурсов, как памяти, так и процессорного времени. Некоторые задачи (например, поиск минимального элемента в массиве) распараллеливаются достаточно легко, другие (сортировка массива) очень трудно распараллелить на системе из процессоров с раздельной памятью.
Для решения всех этих задач нужно применять подходящие для них функции передачи сообщений в MPI, некоторые из них мы затронули в первой работе, рассмотрим теперь остальные.
Коммуникации точка-точка в mpi
В коммуникациях типа «точка-точка» участвуют два процесса (как частный случай процесс может посылать сообщения сам себе). Существуют различные варианты функций отправки и приема сообщений: блокирующие и не блокирующие, с буферизацией, с синхронизацией и по готовности.
Рассмотрим функции блокирующей передачи сообщений – MPI_Send и MPI_Recv:
int MPI_Send(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
Данная функция отправляет данные, находящиеся по адресу buf в количестве count типа datatype процессу с рангом dest с тэгом сообщения tag. Посылка сообщения происходит в коммуникаторе comm. Параметр tag необходим для того, чтобы отличать сообщения от одного и того же процесса, либо сообщения от разных процессов, если принимающий процесс ожидает сообщение от любого процесса.
int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Status *status) – Принимает данные и записывает их по адресу buf в количестве count типа datatype от процесса с рангом dest с тэгом сообщения tag. Прием сообщения происходит в коммуникаторе comm. По адресу status в структуру типа MPI_Status записывается информация о прошедшем приеме сообщения.
typedef struct MPI_Status {
int count; //Сколько байт получено
int cancelled; //Была ли передача прервана
int MPI_SOURCE; //От кого сообщение
int MPI_TAG; //Тэг сообщения
int MPI_ERROR; //Код ошибки
} MPI_Status;
Функции MPI_Send и MPI_Recv являются блокирующими. Возвращение из MPI_Send не происходит до тех пор, пока данные сообщения не будут скопированы во внутренний буфер MPI. MPI_Recv возвращает управление только после того, как сообщение было принято, таким образом, возможно появление взаимных блокировок процессов (deadlock) - ситуаций при который несколько процессов находятся в состоянии бесконечного ожидания ресурсов, занятых самими этими процессами. Блокировка может произойти в случае, когда два процесса попытаются обменяться сообщениями при помощи одинаковой последовательности вызовов (на примере процессов с рангами 0 и 1):
MPI_Send(buffer, 100, MPI_CHAR, !rank, 1, MPI_COMM_WORLD);
MPI_Recv(buffer, 100, MPI_CHAR, !rank, 1, MPI_COMM_WORLD,&st);
Блокировка здесь произойдет сразу во время вызова MPI_Send, так как оба процесса пытаются отправить данные, но ни один еще не начал их принимать. Для избежания таких ситуаций могут использоваться функции совмещенного приема и передачи данных MPI_Sendrecv и
MPI_Sendrecv_replace:
int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
int dest, int sendtag,
void *recvbuf, int recvcount, MPI_Datatype recvtype,
int source, int recvtag,
MPI_Comm comm, MPI_Status *status)
Буфера sendbuf и recvbuf не должны пересекаться. Если необходимо обменяться данными, то следует использовать функцию MPI_Sendrecv_replace.
int MPI_Sendrecv_replace(void *buf, int count, MPI_Datatype datatype,
int dest, int sendtag, int source, int recvtag,
MPI_Comm comm, MPI_Status *status)
Ниже приведен пример обмена данными двух процессов с рангами 0 и 1 при помощи вызова MPI_Sendrecv_replace:
#include <mpi.h>
#include <stdio.h>
static char data[100];
int main(int argc, char** argv)
{
int rank,size;
MPI_Status st;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
if (size!=2)
{
printf("This example should be run on 2 processors \n");
MPI_Finalize();
return 0;
}
if(rank==0) {
sprintf(data, “message from process 0 ”);
} else {
sprintf(data, “message from process 1 ”);
} MPI_Sendrecv_replace(&data,100, MPI_INT, !rank, 0,!rank,0,MPI_COMM_WORLD,&st);
printf("Process %d got %s. \n", rank, data);
MPI_Finalize();
return 0;
}
Результат работы:
Process 0 got message from process 1.
Process 1 got message from process 0.
