- •Введение
- •Порядок выполнения и защиты лабораторных работ
- •Лабораторная работа №1. Определение параметров n-мерных коммутационных структур вс типа гиперкуб, тор и циркулянт
- •Приведение схем алгоритмов к виду, удобному для организации параллельных вычислений.
- •Использование граф-схем для представления параллельных алгоритмов
- •Определение контуров в граф-схеме алгоритма
- •Лабораторная работа №4. Построение матрицы логической несовместимости операторов
- •Лабораторная работа №5. Построение множеств взаимно независимых операторов
- •Лабораторная работа №6. Определение ранних и поздних сроков окончания выполнения операторов и оценка снизу требуемого количества процессоров и времени решения задачи на вс
- •Лабораторная работа №8. Написание программ с использованием библиотеки mpi
- •Определение характеристик таймера
- •Приём и передача сообщений
- •Определения структуры приходящего сообщения
- •Определение базовых характеристик коммуникационной сети
- •Анализ тупиковых ситуаций при обмене
- •Организация передачи-приёма сообщений без блокировки
- •Реализация отложенных запросов на взаимодействие
- •Сравнительная оценка различных способов обмена данными
- •Использование глобальных операций в mpi
- •Взаимодействие процессов в mpi
- •Оглавление
Определение характеристик таймера
В этой программе на каждом процессе определяются две характеристики системного таймера: его разрешение и время, требуемое на замер времени (для усреднения получаемого значения выполняется NTIMES замеров). Также в данном примере показано использование процедуры MPI_GET_PROCESSOR_NAME.
Пример 3:
#include <stdio.h>
#include "mpi.h"
void main(int argc,char * argv[])
{
int n,ierr,rank,len,i,NTIMES=100;
char name[MPI_MAX_PROCESSOR_NAME];
double time_start,time_finish,tick;
MPI_Init(&argc,&argv);
ierr=MPI_Comm_rank(MPI_COMM_WORLD, &rank);
ierr=MPI_Get_processor_name(name, &len);
name[len]=0;
tick=MPI_Wtick();
time_start=MPI_Wtime();
for (n = 0; n<NTIMES; n++) time_finish=MPI_Wtime();
ierr=MPI_Comm_rank(MPI_COMM_WORLD, &rank);
printf("Processor %s, process %i: tick = %d, time = %d\n",name,rank,tick,(time_finish-time_start)/(double)NTIMES);
ierr=MPI_Finalize(); }
Приём и передача сообщений
Передача сообщения использована буферизация. Для буферизации выделяется массив buf, после завершения пересылки он освобождается. Размер необходимого буфера определяется размером сообщения (одно целое число – 4 байта) плюс значение константы MPI_BSEND_ OVERHEAD.
Пример 4:
#include <stdio.h>
#include "mpi.h"
void main(int argc,char * argv[])
{
const int BUFSIZE=MPI_BSEND_OVERHEAD+4;
unsigned char buf[BUFSIZE];
int rank,ierr,ibufsize,rbuf;
struct MPI_Status status;
ierr=MPI_Init(&argc,&argv);
ierr=MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank==0) {
ierr=MPI_Buffer_attach(buf,BUFSIZE);
ierr=MPI_Bsend(&rank,1,MPI_INT,1,5,MPI_COMM_WORLD);
// sending variable rank
ierr=MPI_Buffer_detach(&buf, &BUFSIZE);
}
if (rank==1)
{ ierr=MPI_Recv(&rbuf,1,MPI_INT,0,5,MPI_COMM_WORLD,&status);
printf("Process 1 received %i from process %i\n",rbuf, status.MPI_SOURCE);
}
ierr=MPI_Finalize();
}
Ниже приведен пример программы, в которой нулевой процесс посылает сообщение процессу с номером один и ждет от него ответа. Если программа будет запущена с большим числом процессов, то реально выполнять пересылки все равно станут только нулевой и первый процессы. Остальные процессы после их инициализации процедурой MPI__Init напечатают начальные значения переменных а и b, после чего завершатся, выполнив процедуру MPI_FINALIZE.
Пример 5:
#include <stdio.h>
#include "mpi.h"
void main(int argc,char * argv[])
{
int ierr,size,rank;
float a,b;
MPI_Status status;
ierr=MPI_Init(&argc,&argv);
ierr=MPI_Comm_size(MPI_COMM_WORLD, &size);
ierr=MPI_Comm_rank(MPI_COMM_WORLD, &rank);
a=b=0;
if (rank==0)
{ ierr=MPI_Send(&b,1,MPI_FLOAT,1,5,MPI_COMM_WORLD);
ierr=MPI_Recv(&a,1,MPI_FLOAT,1,5,MPI_COMM_WORLD,&status);
} else
if (rank==1)
{
a=2;
ierr=MPI_Recv(&b,1,MPI_FLOAT,0,5,MPI_COMM_WORLD,&status);
ierr=MPI_Send(&a,1,MPI_FLOAT,0,5,MPI_COMM_WORLD);
printf("Process %i a = %lf b = %lf\n",rank,a,b); }
ierr=MPI_Finalize();
}
В следующем примере каждый процесс с четным номером посылает сообщение своему соседу с номером на единицу большим. Дополнительно поставлена проверка для процесса с максимальным номером, чтобы он не послал сообщение несуществующему процессу. Значения переменной b изменятся только на процессах с нечетными номерами.
Пример 6:
#include <stdio.h>
#include "mpi.h"
void main(int argc,char * argv[])
{
int ierr,size,rank,a,b;
struct MPI_Status status;
ierr=MPI_Init(&argc,&argv);
ierr=MPI_Comm_size(MPI_COMM_WORLD, &size);
ierr=MPI_Comm_rank(MPI_COMM_WORLD, &rank);
a=rank;
b=-1;
if (rank%2==0)
{
if (rank+1<size)
ierr=MPI_Send(&a, 1, MPI_INT, rank+1, 5, MPI_COMM_WORLD);
}
else ierr=MPI_Recv(&b,1,MPI_INT,rank-1,5,MPI_COMM_WORLD,&status);
printf ("Process %i a = %i b = %i\n",rank,a,b) ;
ierr=MPI_Finalize (); }
Задание: Измените данную программу так, чтобы нулевой процесс не посылал сообщений и запустите её с числом процессов, равным номеру вашего варианта.
Процессы приложения в приводимой ниже программе разбиваются на две непересекающиеся примерно равные группы groupl и group2. При нечетном числе процессов в группе group2 может оказаться на один процесс больше, тогда последний процесс из данной группы не должен обмениваться данными ни с одним процессом из группы groupl. С помощью вызовов процедуры MPI_Group_translate_ranks каждый процесс находит процесс с тем же номером в другой группе и обменивается с ним сообщением через коммуникатор MPl_COMM_WORLD при помощи вызова процедуры MPI_Sendrecv. В конце программы не нужные далее группы уничтожаются с помощью вызовов процедур MPI_GROUP_FREE.
Пример 7:
#include <stdio.h>
#include "mpi.h"
void main(int argc,char * argv[])
{
int ierr,rank,i,size,size1;
const int n=1000;
int a[4],b[4];
int ranks[128], rank1, rank2, rank3;
MPI_Status status;
MPI_Group group,group1,group2;
ierr=MPI_Init(&argc,&argv);
ierr=MPI_Comm_size(MPI_COMM_WORLD,&size);
ierr=MPI_Comm_rank(MPI_COMM_WORLD, &rank) ;
ierr=MPI_Comm_group(MPI_COMM_WORLD, &group);
size1=size/2;
for (i=0;i<size1;i++)
ranks[i]=i;
ierr=MPI_Group_incl(group,size1,ranks, &group1);
ierr=MPI_Group_excl(group,size1,ranks, &group2);
ierr=MPI_Group_rank (group1, &rank1);
ierr=MPI_Group_rank(group2,&rank2);
if (rank1==MPI_UNDEFINED) // we are in second half
{ if (rank2<size1)
ierr=MPI_Group_translate_ranks(group1,1,&rank2,group,&rank3); else rank3=MPI_UNDEFINED;
}
else // in first half
ierr=MPI_Group_translate_ranks(group2,1,&rank1,group,&rank3);
a[0]=rank;
a[1]=rank1;
a[2]=rank2;
a[3]=rank3;
if (rank3!=MPI_UNDEFINED)
ierr=MPI_Sendrecv(a,4,MPI_INT,rank3,1,b,4,MPI_INT,rank3,1,MPI_COMM_WORLD,&status);
ierr=MPI_Group_free(&group) ;
ierr=MPI_Group_free(&group1);
ierr=MPI_Group_free(&group2);
printf ( "Process %i a=[",rank);
for ( i=0;i<4;i++) printf("%i ",a[i]);
printf ("] b=[");
for ( i=0;i<4;i++) printf ("%i ",b[i]);
printf("]\n");
ierr=MPI_Finalize();
}
Задание: Измените программу так, чтобы передаваемые сообщения содержали номер передающего процесса и ваше имя.
