- •Федеральное агентство по атомной энергии
- •Национальный исследовательский ядерный университет «мифи»
- •Средства разработки параллельных приложений на общей и распределенной памяти в стандарте интерфейса передачи данных mpi и openmp c реализации курс лекций
- •Void main(int argc, char *argv[] ){
- •Int rank, size;
- •Int mpi_Send(void* buf, int count, mpi_Datatype datatype, int dest, int tag, mpi_Comm comm)
- •Int mpi_Get_count(mpi_Status *status, mpi_Datatype datatype, int *count)
- •Стандартный режим передачи
- •Буферизующий режим передачи
- •1. Барьерная синхронизация - mpi_Barrier (comm)
- •2. Широковещательная передача
- •3. Сбор данных
- •4. Рассылка данных
- •5. Операции редукции (обработки данных)
- •Непрерывный.
- •2. Вектор
- •Int mpi_Type_hvector(int count, int blocklength, int stride, mpi_Datatype oldtype,
- •4. Индексированные данные
- •6. Структурный
- •3. Mpi_Group_translate_ranks (mpi_Group group1, int n, int *ranks1, mpi_Group group2, int *ranks2)
- •4. Mpi_Group _compare(group1, group2, result)
- •6. Mpi_Group _excl(group, n, ranks, newgroup)
- •1. Mpi_Comm_size (comm, size)
- •2. Mpi_Comm_rank(comm, rank)
- •3. Mpi_Comm_compare(comm1, comm2, result)
- •1. Mpi_Comm_dup(comm, newcomm)
- •2. Mpi_Comm_create(comm, group, newcomm)
- •3. Mpi_Comm_split(comm, color, key, newcomm)
- •1. Mpi_Cart_create(mpi_Comm comm_old, int ndims, int *dims, int *periods, int reorder, mpi_Comm *comm_cart)
- •2. Mpi_Dims_create(int nnodes, int ndims, int *dims)
- •1. Mpi_Cartdim_get(mpi_Comm comm, int *ndims)
- •2. Mpi_Cart_get(mpi_Comm comm, int maxdims, int *dims, int *periods, int *coords)
- •3. Int mpi_Cart_rank(mpi_Comm comm, int *coords, int *rank)
- •4. Int mpi_Cart_coords(mpi_Comm comm, int rank, int maxdims, int *coords)
- •5. Координаты декартова сдвига
- •Int mpi_Graph_create(mpi_Comm comm_old, int nnodes, int *index, int *edges, int reorder, mpi_Comm *comm_graph)
- •Int mpi_Topo_test(mpi_Comm comm, int *status)
- •Default(shared | none)
- •Void main()
- •Void main()
- •Int a[10], b[10], c[10]; // целочисленные массивы
- •2. Оператор sections
- •3. Оператор single
- •Void main()
- •10. Функция omp_get_nested
- •Int omp_get_nested(void)
6. Структурный
MPI_Type_struct общий конструктор: он обобщает предыдущий конструктор таким образом, что позволяет каждому блоку состоять из различных типов данных.
MPI_Type_struct (count, array_of_blocklengths, array_of_displacements, array_of_types, newtype)
IN |
count |
количество блоков (int) |
IN |
array_of_blocklengths |
число элем-ов в каждом блоке (массив int длиной count) |
IN |
array_of_displacements |
смещение каждого блока в байтах (массив int длиной count) |
IN |
array_of_types |
тип элемента в каждом блоке (массив типов длиной count) |
OUT |
newtype |
новый тип данных (handle) |
Пример Пусть type1 имеет карту типа {(double, 0), (char, 8)}, с протяжённостью 16. Пусть B=(2,1,3), D=(0,16,26), и T=(MPI_FLOAT, type1, MPI_CHAR). Тогда вызов MPI_TYPE_STRUCT(3, B, D, T, newtype) создает тип данных с картой,
{(float,0), (float,4), (double,16), (char,24), (char,26), (char,27), (char,28)}:
две копии MPI_FLOAT начинаются с 0, затем копия типа type1 начинается с 16, далее идут три копии MPI_CHAR, начинающиеся с 26.
Пример. Копирование нижней треугольной части матрицы. Для создания нового типа данных используем MPI_Type_indexed
#include <mpi.h>
#include <iostream.h>
void main( int argc, char *argv[] ) {
int a[8][8], b[8][8];
int disp[8], block[8];
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Status stat;
for(i=0; i<8; i++){
for(int j=0; j<8; j++){
a[i][j]= (j<=i)?(i+1):0;
cout<<a[i][j]<<"\t";
}
cout<<endl;
}
// копирует нижнюю треугольную часть матрицы a в нижнюю треугольную часть
// матрицы b
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// вычисляет начало и размер каждого блока (блок – это строка матрицы)
disp[0] = 0;
block[0] = 1;
for (i=1; i<8; i++){
disp[i] = 8*i;
block[i] = i+1;
}
// создание типа данных для нижней треугольной части матрицы, далее этот тип
// данных можно использовать в обменах
MPI_Datatype my_type; //объявили имя нового типа данных
MPI_Type_indexed(count, block, disp, MPI_INT, &my_type);
MPI_Type_commit(&my_type); //зафиксировали новый тип данных
if(rank==0)
MPI_Send(a, 1, my_type, 1, 99, MPI_COMM_WORLD);
if(rank==1){
MPI_Recv(b, 1, my_type, 0, 99, MPI_COMM_WORLD, &stat);
cout<<endl<<"RESULT MATRIX"<<endl;
for(i=0; i<8; i++){
for(int j=0; j<8; j++){
cout<<((j<=i)?b[i][j]:0)<<"\t";
}
cout<<endl;
}
}
MPI_Finalize();
}
Лекция 6
Адресные функции и функции экстентов. Конструкторы групп и коммуникаторов. Интракоммуникаторы.
Функция MPI_Address возвращает байтовый адрес элемента (ячейки)
MPI_Address (location, address)
IN location элемент (ячейка в памяти)
OUT address адрес ячейки (целое)
Пример Использование MPI_Address для вещественного массива.
double m[100];
MPI_Aint i1, i2, diff; // MPI_Aint – это long
MPI_Address(&m[0], &i1);
MPI_Address(&m[9], &i2);
diff = i2 – i1;
значение diff есть 9*sizeof(double) =72.
Функция MPI_Type_extent возвращает экстент (протяженность типа данных) типа данных.
MPI_Type_extent(datatype, extent)
IN datatype тип данных (дескриптор)
OUT extent экстент типа данных (целое)
Функция MPI_Type_size возвращает общий размер в байтах типа данных, указанного в datatype.
MPI_Type_size (datatype, size)
IN datatype тип данных (дескриптор)
OUT size размер типа данных (целое)
Маркеры нижней и верхней границ
Часто удобно явно указать нижнюю и верхнюю границы карты типа. Это позволяет определить тип данных, который имеет «дыры» в начале или конце, или тип с элементами, которые идут выше верхней или ниже нижней границы. Пользователь может явно описать границы типа данных, которые соответствуют этим структурам.
Псевдо тип данных: MPI_LB используется для маркировки нижней границы типа данных, MPI_UB используется для маркировки верхней границы типа данных. Маркеры границ не занимают места в памяти, их размер равен 0 (экстент (MPI_LB) = экстент (MPI_UB) =0), они не меняют size или count типа данных и не влияют на содержание сообщения, выполняемого с этим типом данных. Маркеры границ влияют на определение экстента типа данных и, следовательно, влияют на результат репликации (отображения) этого типа данных конструктором типа данных.
Функции представленные ниже могут быть использованы для нахождения нижней и верхней границ типа данных.
MPI_Type_lb ( datatype, displacement)
IN datatype тип данных (дескриптор)
OUT displacement смещение нижней границы от исходной в байтах (целое)
MPI_Type_ub ( datatype, displacement)
IN datatype тип данных (дескриптор)
OUT displacement смещение верхней границы от исходной в байтах (целое)
Напомню, что количество полученных в сообщении элементов можно определить функцией MPI_Get_count. Также количество полученных в сообщении элементов можно получить с помощью функции MPI_Get_elements.
MPI_Get_elements ( status, datatype, count)
IN status статус операции приема (статус)
IN datatype тип данных операции приема (дескриптор)
OUT count число принятых базисных элементов (целое)
Функция MPI_Get_elements может использоваться после операции probe, чтобы определить число элементов в сообщении. Заметим, что две функции MPI_Get_count и MPI_Get_elements возвращают то же самое значение, когда они используются с базисным типом данных.
Группы и коммуникаторы
Интерфейс MPI использует такие понятия, как группы процессов (groups), виртуальные топологии (virtual topologies) и коммуникаторы (communicators).
Коммуникаторы создают область для всех операций обмена в MPI. Коммуникаторы разделяются на два вида: интра-коммуникаторы - внутригрупповые коммуникаторы, предназначенные для операций в пределах группы процессов, и интер-коммуникаторы - межгрупповые коммуникаторы, предназначенные для обменов между двумя группами процессов. Начальный для всех процессов интра-коммуникатор MPI_COMM_WORLD, который создается сразу при обращении к функции MPI_INIT. Удалить коммуникатор MPI_COMM_WORLD нельзя. Кроме того, существует коммуникатор, который содержит только себя как процесс – MPI_COMM_SELF.
Группы определяют упорядоченную набор процессов по именам, именами процессов являются их порядковые номера. Группы определяют область для выполнения обменов, но в операциях обмена могут использоваться только коммуникаторы. Группа определена в пределах коммуникатора. В MPI определена предопределенная группа: MPI_GROUP_EMPTY – это группа без процессов.
Виртуальная топология определяет отображение номеров процессов в группе на определенную топологию, и наоборот. Для создания виртуальных топологий определены специальные конструкторы, рассматривать которые будем позже.
Управление группой
Операции управления являются локальными, и их выполнение не требует меж процессного обмена.
Функции доступа к группе
1. MPI_Group_size(MPI_Group group, int *size) позволяет определить размер группы.
IN group группа (дескриптор)
OUT size количество процессов в группе (целое)
2. MPI_Group_rank(MPI_Group group, int *rank) служит для определения номера процесса в группе.
IN group группа (дескриптор)
OUT rank номер процесса в группе или MPI_UNDEFINED, если процесс не является членом группы (целое)
