Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Пример. Функция MPI_Reduce с операцией MPI_SUM




#include <stdio.h>

#include <mpi.h>

void main( int argc, char *argv[] ) {

int a[]={1,4,7,2,1,9,6,8,3,5}, summa[10];

int i, rank;

 

MPI_Init( &argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

 

MPI_Reduce(&a[0],&summa[0],10,MPI_INT,MPI_SUM,1,MPI_COMM_WORLD );

 

if (rank ==1) { //результат помещается на root процесс, root=1

for (i=0; i<10; i++) {

printf("%d\n", summa[i]);

}

}

MPI_Finalize();

}

 

 

  1. Принцип взаимодействия параллельных процессов при выполнении обобщенных коллективных операций сборки и рассылки данных.

Сбор данных

MPI_Gather(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, int root, comm);

IN sendbuf начальный адрес буфера передачи сообщения

IN sendcount количество элементов в отсылаемом сообщении (целое)

IN sendtype тип элементов в отсылаемом сообщении

OUT recvbuf начальный адрес буфера сборки данных (исп-ся только корневым проц.)

IN recvcount колич. элем-ов в принимаемом сообщении (исп-ся только корневым проц.)

IN recvtype тип элементов в получаемом сообщения на процессе-получателе

IN root номер процесса-получателя (целое)

IN comm коммуникатор (дескриптор)

 

При выполнении операции сборки данных MPI_Gather каждый процесс, включая корневой, посылает содержимое своего буфера в корневой процесс. Корневой процесс получает сообщения и располагает их в порядке возрастания номеров процессов.

Выполнение MPI_Gather будет давать такой же результат, как если бы каждый из n процессов группы (включая корневой процесс) выполнил вызов MPI_Send (sendbuf, sendcount, sendtype, root, …), а принимающий процесс выполнил n вызовов MPI_Recv(recvbuf + i * recvcount * extent(recvtype), recvcount, recvtype, i, …)

Количество посланных и полученных данных должно совпадать, т.е. sendcount== recvcount. Аргумент recvcount в главном процессе показывает количество элементов, которые он получил от каждого процесса, а не общее количество полученных элементов.

В корневом процессе используются все аргументы функции, на остальных процессах используются только аргументы sendbuf, sendcount, sendtype, root, comm. Аргументы comm и root должны иметь одинаковые значения во всех процессах.

 

MPI_Gatherv(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, root, comm)

IN sendbuf начальный адрес буфера отправителя

IN sendcount количество элементов в отсылаемом сообщении (целое)

IN sendtype тип элементов в отсылаемом сообщении

OUT recvbuf адрес буфера процесса сборки данных (существ-но для корневого процесса)

IN recvcounts массив цел. чисел (gsize), содержит количество элементов, полученных от каждого процесса (используется корневым процессом)

IN displs массив целых чисел (gsize). Эл-нт i определяет смещение относит. recvbuf, в котором размещаются данные из процесса i (исп-ся корневым процессом)

IN recvtype тип данных элементов в буфере процесса-получателя

IN root номер процесса-получателя (целое)

IN comm коммуникатор

 

MPI_Gatherv имеет аналогичные параметры, за исключением int* recvcounts и int*displs – это массивы целых чисел, размеры которых равны размеру группы (числу процессов).

В отличие от MPI_Gather при использовании функции MPI_Gatherv разрешается принимать от каждого процесса переменное число элементов данных, поэтому в функции MPI_Gatherv аргумент recvcounts является массивом. Если Вы выполняете операцию вне ветки какого-либо процесса, значение sendcount будет одно для всех процессов в группе. Для того, чтобы процессы могли выполнить операцию с различным sendcount функцию надо вызывать в каждой ветке, определяющей код процесса, правильно определяя значения элементов массива recvcounts на корневом процессе.

Выполнение MPI_Gatherv будет давать такой же результат, как если бы каждый процесс, включая корневой, посылал корневому процессу сообщение: MPI_Send(sendbuf, sendcount, sendtype, root, …), а принимающий процесс выполнил n операций приема: MPI_Recv(recvbuf+displs[i]*extern(recvtype), recvcounts[i], recvtype, i, …).

Сообщения помещаются в буфер принимающего процесса в порядке возрастания номеров процессов, от которых они приходят, то есть данные, посланные процессом i, помещаются в i-ю часть принимающего буфера recvbuf на корневом процессе. i-я часть recvbuf начинается со смещения displs[i].

В принимающем процессе используются все аргументы функции MPI_Gatherv, а на всех других процессах используются только аргументы sendbuf, sendcount, sendtype, root, comm. Переменные comm и root должны иметь одинаковые значения во всех процессах.

5. Рассылка данных

 

MPI_Scatter(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm);

IN sendbuf адрес буфера рассылки (исп-ся только корневым проц.)

IN sendcount кол-во эл-ов, посылаемых каждому процессу (исп-ся корневым проц.)

IN sendtype тип данных элементов в буфере посылки (исп-ся корневым проц.)

OUT recvbuf адрес буфера процесса-получателя

IN recvcount количество элементов в буфере корневого процесса (целое)

IN recvtype тип данных элементов приемного буфера

IN root номер процесса-получателя (целое)

IN comm коммуникатор (дескриптор)

 

MPI_Scatter – обратная функция по отношению к MPI_Gather. Результат ее выполнения таков, как если бы корневой процесс выполнил n операций посылки: MPI_Send(senbuf + i * extent(sendtype), sendcount, sendtype, i, …), и каждый процесс выполнит прием: MPI_Recv(recvbuf, recvcount, recvtype, i, …).

Значения sendcount[i], sendtype на главном процессе, должны быть теми же, что и recvcount, recvtype на процессе i. Количество посланных и полученных данных должно совпадать для всех процессов. Процесс, который выполняет рассылку использует все аргументы функции, принимающие процессы используют только аргументы recvbuf, recvcount, recvtype, root, comm. Аргументы root и comm должны быть одинаковыми во всех процессах.

 

  1. Типы данных MPI. Понятие производных типов данных MPI. Конструкторы производных типов данных.

Типы данных MPI

При выполнении операций передачи сообщений в функциях MPI необходимо указывать тип пересылаемых данных. MPI содержит набор базовых типов данных, во многом совпадающих с типами данных в алгоритмических языках C и Fortran. Кроме того, в MPI содержит функции для создания производных типов данных. Все типы данных MPI содержатся в файле mpi.h Аналогично функциям MPI, базовые типы данных имеют префикс MPI, например, MPI_INT, MPI_DOUBLE и т.д. В стандарте MPI не предусмотрен механизм преобразование типов данных, используемый в Си.

 

При выполнении передачи данных между процессами определяется буфер передачи данных и буфер приема данных. В операциях обмена указывается количество передаваемых/принимаемых данных в единицах данных и тип этих данных. На основании этой информации формируется буфер обмена, размер которого равен числу элементов, умноженному на размер типа данных в байтах. Если в принимающем процессе определить другой тип, что произойдет? Данные будут получены при достаточном размере приемного буфера, но получить правильное значение полученных данных будет проблематично.

При выполнении операций обмена типы данных типы переданных и полученных данных должны совпадать.

Конструкторы типов данных. Функции упаковки и распаковки данных.

Поддерживаемые MPI языки программирования, в частности Си имеют средства создания собственных “нестандартных” типов данных, например, с помощью структур. Но передать за одну отправку переменные такого типа мы не можем. Почему? Проблема заключается в том, что в функциях передачи и приемы в качестве параметра, который определяет длину сообщения, используется количество передаваемых данных в единицах данных типа. Длина сообщения вычисляется как произведение указанного типа данных на число элементов.

Другая проблема заключается в том, что мы не можем передать за одну отправку, используя стандартные типы данных MPI переменные разных типов, например int и double или более сложные конструкции, например структуры с различными по типу и размеру полями. Выполнить такую передачу можно несколькими способами:

1. преобразовать данные меньшего типа к большему, в данном случае int к double. Естественно, что при выполнении такой передачи длина сообщения будет больше, поскольку каждый 4-ух байтовый int будет преобразован в 8-ми байтовый double. Поэтому, чем больше данных типа int и меньше данных типа double, тем больше увеличится объем передаваемого сообщения. Это неэффективно.

2. использовать операцию упаковки и распаковки. Это лучше предыдущего способа, но если необходимо часто передавать нестандартные данные, то многократный вызов операций MPI_Pack/MPI_Unpack также приводят к дополнительным накладным расходам, поскольку выполняют большую работу по переписыванию данных из одной области памяти в другую. Что при больших объемах данных занимает достаточно много времени.

3. Создать новый тип данных и использовать его на протяжении всей работы программы.

 

Операции упаковки и распаковки данных

Тип MPI_PACKED используется для передачи данных, которые были явно упакованы, или для получения данных, которые будут явно распакованы.

 

MPI_Pack (inbuf, incount, datatype, outbuf, outsize, position, comm)

IN inbuf начало входного буфера (альтернатива)

IN incount число единиц входных данных (целое)

IN datatype тип данных каждой входной единицы (дескриптор)

OUT outbuf начало выходного буфера (альтернатива)

IN outsize размер выходного буфера в байтах (целое)

INOUT position текущая позиция в буфере в байтах (целое)

IN comm коммуникатор для упакованного сообщения

 

MPI_Pack пакует сообщение из буфера передачи, который определяется аргументами inbuf, incount, datatype в выходной буфер. Выходной буфер это непрерывная область памяти, содержащая outsize байтов, начиная с адреса outbuf (длина подсчитывается в байтах, а не элементах).

Входное значение position - это первая ячейка в выходном буфере, которая используется для упаковки. Далее рosition увеличивается на размер упакованного сообщения (в байтах), таким образом выходное значение рosition - это первая ячейка в выходном буфере, следующая за упакованным сообщением.

 

MPI_Unpack (inbuf, insize, position, outbuf, outcount, datatype, comm)

IN inbuf начало входного буфера (альтернатива)

IN insize размер входного буфера в байтах (целое)

INOUT position текущая позиция в байтах (целое)

OUT outbuf начало выходного буфера (альтернатива)

IN outcount число единиц для распаковки (целое)

IN datatype тип данных каждой выходной единицы данных (дескриптор)

IN comm коммуникатор для упакованных сообщений (дескриптор)

 

MPI_Unpack распаковывает сообщение в приемный буфер, который определяется аргументами outbuf, outcount, datatype из буфера, определенного аргументами inbuf и insize. Входной буфер - это непрерывная область памяти, содержащая insize байтов, начиная с адреса inbuf.

Входное значение position есть первая ячейка во входном буфере, занятом упакованным сообщением. Далее значение рosition увеличивается на размер упакованного сообщения, таким образом выходное значение рosition - это первая ячейка во входном буфере после сообщением, которое было упаковано.

 

В основном функции используются в том случае, если необходимо сформировать один буфер передачи из нескольких. В этом случае, выполняется несколько последовательно связанных обращений к MPI_Pack, где первый вызов определяет position = 0, и каждый последующий вызов вводит значение position, которое было выходом для предыдущего вызова, и то же самое значение для outbuf, outcount. Этот упакованный объект содержит эквивалентное сообщение, которое выполнялось бы по одной передаче отдельно с каждым буфером передачи.

Упакованный объект передается и принимается с типом MPI_PACKED любой операцией передачи сообщений (двухточечной или коллективной) с последующей распаковкой.

 

Если упакованный объект был последовательно сформирован из нескольких буферов, т.е. выполнено несколько операций MPI_Pack, то он может быть распакован в несколько последовательных сообщений последовательностью вызовов функции MPI_Unpack, где первый вызов определяет position = 0, а каждый последующий вызов вводит значение position, которое было выходом предыдущего обращения.

Очевидно, что количество упаковок должно совпадать с количеством распаковок.

 

Следующий вызов позволяет определить, объем памяти, который необходимо выделить для упаковки сообщений.

MPI_Pack_size(incount, datatype, comm, size)

IN incount аргумент count для упакованного вызова (целое)

IN datatype аргумент datatype для упакованного вызова (дескриптор)

IN comm аргумент communicator для упакованного вызова (дескриптор)

OUT size верхняя граница упакованного сообщения в байтах (целое)

 

Функция MPI_Pack_size возвращает в size верхнюю границу значения position, которая создана обращением к функции упаковки MPI_Pack.

 

Пример. Функция MPI_Pack/MPI_Unpack

#include <stdio.h>

#include <mpi.h>

void main( int argc, char *argv[] ) {

int ii, iii=2;

double jj, jjj=5.3;

int position, count;

char buff_pack[100], buff_unpack[100];

MPI_Status stat;

 

if (rank == 0) {

position = 0;

MPI_Pack(&iii,1,MPI_INT,buff_pack,100, &position, MPI_COMM_WORLD);

MPI_Pack(&jjj,1,MPI_DOUBLE,buff_pack,100,&position, MPI_COMM_WORLD);

 

MPI_Send(&buff_pack[0], position, MPI_PACKED, 1, 0, MPI_COMM_WORLD);

}

else {

MPI_Probe(0, 0, MPI_COMM_WORLD, &stat);

MPI_Get_count(&stat, MPI_PACKED, &count);

MPI_Recv( &buff_unpack[0], count, MPI_PACKED, 0, 0, MPI_COMM_WORLD, &stat);

 

position = 0;

MPI_Unpack(&buff_unpack[0],count,&position, &ii,1, MPI_INT, MPI_COMM_WORLD);

MPI_Unpack(&buff_unpack[0],count,&position, &jj,1, MPI_DOUBLE,

MPI_COMM_WORLD);

printf("ii=%d jj=%f\n",ii,jj);

}

 

MPI_Finalize();

}

 

MPI содержит механизм, который позволяет передавать данные различной структуры и размера, выполняя передачу данные непосредственно из памяти, т.е. без дополнительного копирования. Аналогично тому, как создаются производные типы данных в Си, производные типы данных MPI, конструируются из базовых типов с использованием специальных конструкторов.

В общем случае описываемые значения не обязательно непрерывно располагаются в памяти. Каждый тип данных MPI имеет карту типа (type map), состоящую из последовательности пар значений, первое задает базовых тип данных, второе - смещение адреса в памяти относительно начала базового адреса, т.е.

 

Часть карты типа с указанием только базовых типов называется сигнатурой типа:

 

Сигнатура типа описывает, какие базовые типы данных образуют производный тип данных MPI. Смещения карты типа определяют, где находятся значения данных.

Например, пусть в сообщение должны входить значения переменных:

double a; /* адрес 24 */

double b; /* адрес 40 */

int n; /* адрес 48 */

Тогда производный тип для описания таких данных должен иметь карту типа следующего вида: { (MPI_DOUBLE,0), (MPI_DOUBLE,16), (MPI_INT,24) }

Для характеристики типа данных в MPI используется следующий ряд понятий:

- нижняя граница типа

- верхняя граница типа

- протяженность типа extent(TypeMap) = ub(TypeMap)-lb(TypeMap).

Нижняя граница – определяет смещение для первого байта значений типа данных.

Верхняя граница – определяет смещение для байта, расположенного за последним элементом типа данных. При этом величина смещения для верхней границы может быть округлена вверх с учетом требований выравнивания адресов.

Понятие протяженности отличается от понятия размер типа. Протяженность – это размер памяти в байтах, который нужно отводить для одного элемента производного типа. Размер типа данных - это число байтов, которые занимают в памяти данные (разность между адресами последнего и первого байтов данных). Отсюда - различие в значениях протяженности и размера зависит от величины округления при выравнивании адресов. Так, в рассматриваемом примере размер типа равен 28, а протяженность – 32 (предполагается, что выравнивание выставлено на 8 байт).

Итак, создание общего типа данных определяется:

• последовательностью базовых типов данных,

• последовательностью смещений байтов.

 

1. Непрерывный.

Конструирует новый тип данных, размножением старого типа данных в непрерывную область памяти.

MPI_Type_contiguous(count, oldtype, newtype)

IN count число повторений (неотрицательное целое)

IN oldtype старый тип данных (дескриптор)

OUT newtype новый тип данных (дескриптор)

 

newtype это тип данных, полученный размножением count копий oldtype.

 

Сконструированный объект типа данных должен быть зафиксирован перед тем, как он может быть использован в обменах. Функция, которая фиксирует новый тип данных имеет следующий вид:

MPI_Type_commit (datatype)

INOUT Datatype тип данных, который фиксируется (handle)

 

После того, как тип данных был объявлен, он может быть использован для выполнения обменов и других операций с типами данных. На его основе может быть создан уже новый тип данных.

 

Освобождение созданного типа данных

MPI_Type_free (datatype)

INOUT datatype тип данных, который освобождается (handle)

Устанавливает datatype в MPI_DATATYPE_NULL.

 

2. Вектор

Выполняет размножение типов данных, которые состоят из равных блоков. Интервал между блоками кратно протяжённости старого типа данных.

MPI_Type_vector(count, blocklength, stride, oldtype, newtype)

IN count число блоков (int)

IN blocklength число элементов в каждом блоке (int)

IN stride число элементов между началом каждого блока (int)

IN oldtype старый тип данных

OUT newtype новый тип данных

Пример: пусть, oldtype имеет карту типа {(double, 0), (char,8)}, с протяжённостью 16. Вызов MPI_Type_vector(2, 3, 4, oldtype, newtype) создаст тип данных с картой:

{(double, 0), (char, 8), (double, 16), (char, 24), (double, 32), (char, 40), (double, 64), (char, 72), (double, 80), (char, 88), (double, 96), (char, 104)}.

Это два блока с тремя копиями старого типа в каждом, с шагом 4 элемента (416 байтов) друг от друга.

Вызов MPI_Type_contiguous (count, oldtype, newtype) эквивалентен вызову MPI_Type_vector (count, 1, 1, oldtype, newtype)

 

3. Hвектор

Функция MPI_Type_hvector аналогична MPI_Type_vector, за исключением того, что stride задается в байтах, а не в элементах, поэтому смещение возможно на произвольное число байт. Символ h добавляет смысл heterogeneous – неоднородность.

int MPI_Type_hvector(int count, int blocklength, int stride, MPI_Datatype oldtype,

MPI_Datatype *newtype)

IN count число блоков

IN blocklength число элементов в каждом блоке

IN stride число байт между началом каждого блока

IN oldtype старый тип данных

OUT newtype новый тип данных

 

4. Индексированные данные

Функция MPI_Type_indexed выполняет размножение старого типа в последовательность блоков (каждый блок это конкатенация старого типа данных), где каждый блок может содержать различное число копий и иметь различное смещение. Все смещения блоков кратны протяжённости старого типа.

MPI_Type_indexed (count, array_of_blocklengths, array_of_displacements, oldtype, newtype)

IN count число блоков

IN array_of_blocklengths число элементов в каждом блоке (массив длиной count)

IN array_of_displacements смещение каждого блока, в количестве протяжённостей oldtype (массив длиной count)

IN oldtype старый тип данных

OUT newtype новый тип данных

Пример Пусть oldtype имеет карту типа {(double, 0), (char, 8)}, c протяженностью 16. Пусть B = (3,1) и пусть D = (4,0). Вызов MPI_Type_indexed (2, B, D, oldtype, newtype) возвращает тип данных с картой типа {(double, 64), (char, 72), (double, 80), (char, 88), (double, 96), (char, 104), (double, 0), (char, 8)}: три карты старого типа, начинающиеся со смещения 64, и одна копия, начинающаяся со смещения 0.

 

Вызов MPI_Type_vector (count, blocklength, stride, oldtype, newtype) эквивалентен вызову MPI_Type_indexed (count, B, D, oldtype, newtype), где

 

Функция MPI_Type_hindexed идентична MPI_Type_indexed, за исключением того, что смещения между блоками в array_of_displacements определены в байтах, а не в значениях, кратных протяжённости oldtype. Буква h добавляет смысл heterogeneous – неоднородность.

MPI_Type_hindexed(count, array_of_blocklengths, array_of_displacements, oldtype, newtype)

IN count число блоков - также число элементов в array_of_displacements и array_of_blocklengths (nonnegative integer)

IN array_of_blocklengths число элементов в каждом блоке (массив nonegative integer)

IN array_of_displacements смещение каждого блока, в байтах (массив integer)

IN oldtype старый тип данных (handle)

OUT newtype новый тип данных (handle)

 

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();

}

 

  1. Управление группами процессов и коммуникаторами. Конструирование групп и коммуникаторов.

Группы и коммуникаторы

 

Интерфейс 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, если процесс не является членом группы (целое)

 

3. MPI_Group_translate_ranks (MPI_Group group1, int n, int *ranks1, MPI_Group group2, int *ranks2)

IN group1 группа1 (дескриптор)

IN n число номеров в массивах ranks1 и ranks2 (целое)

IN ranks1 массив из номеров процессов в группе1

IN group2 группа2 (дескриптор)

OUT ranks2 массив соответствующих номеров процессов в группе2, MPI_UNDEFINED, если соответствие отсутствует.

 

Функция MPI_Group_translate_ranks определяет относительную нумерацию одинаковых процессов в двух различных группах. Например, если известны номера некоторых процессов в MPI_COMM_WORLD, то можно узнать их номера в подмножестве этой группы.

 

4. MPI_Group _compare(group1, group2, result)

group1 первая группа (дескриптор)

group2 вторая группа (дескриптор)

OUT result результат (целое)

Функция MPI_Group_compare сравнивает группы. Если члены группы и их порядок в обеих группах одинаковы, результат будет MPI_IDENT. Если члены группы одинаковы, но порядок различен, то результат будет MPI_SIMILAR. В остальных случаях - MPI_UNEQUAL.

 

Конструкторы групп

Конструкторы создают новые группы на основе существующих групп. Данные операции являются локальными, и различные группы могут быть определены на различных процессах.

 

MPI не имеет механизма для формирования группы с нуля – группа может формироваться только на основе другой, предварительно определенной группы. Базовая группа, на основе которой определены все другие группы, является группой, связанной с коммуникатором MPI_COMM_WORLD (через функцию MPI_COMM_GROUP).

 

1. MPI_Comm_group(MPI_Comm comm, MPI_Group *group)

IN comm коммуникатор (дескриптор)

OUT group группа, соответствующая comm (дескриптор)

 

Функция MPI_Comm_group возвращает в group дескриптор группы из comm.

 

2. MPI_Group_union(MPI_Group group1, MPI_Group group2, MPI_Group *newgroup)

IN group1 первая группа (дескриптор)

IN group2 вторая группа (дескриптор)

OUT newgroup объединенная группа (дескриптор)

 

Объединение (union) – содержит все элементы первой группы (group1) и следующие за ними элементы второй группы (group2), не входящие в первую группу.

 

3. MPI_Group_intersection(MPI_Group group1, MPI_Group group2,MPI_Group *newgroup)

IN group1 первая группа (дескриптор)

IN group2 вторая группа (дескриптор)

OUT newgroup группа, образованная пересечением (дескриптор)

 

Пересечение (intersect) – содержит все элементы group1, которые также находятся в group2 и упорядоченные, как в первой группе.

 

4. MPI_Group_difference(MPI_Group group1, MPI_Group group2,MPI_Group *newgroup)

IN group1 первая группа(дескриптор)

IN group2 вторая группа (дескриптор)

OUT newgroup исключенная группа (дескриптор)

 

Разность (difference) – содержит все элементы group1, которые не находятся в group2.

 

5. MPI_ Group_incl(group, n, ranks, newgroup)

IN group группа (дескриптор)

IN n количество элементов в массиве номеров (и размер newgroup, целое)

IN ranks номера процессов в group, перешедших в новую группу (массив целых)

OUT newgroup новая группа, полученная из прежней, упорядоченная согласно ranks

Cоздает новую группу, которая состоит из n процессов исходной группы group с номерами rank[0],..., rank[n-1]; процесс с номером i в newgroup есть процесс с номером ranks[i] в group. Если n = 0, то newgroup имеет значение MPI_GROUP_EMPTY.

 

 

6. MPI_Group _excl(group, n, ranks, newgroup)

IN group группа (дескриптор)

IN n количество элементов в массиве номеров (целое)

IN ranks массив целочисленных номеров в group, не входящих в newgroup

OUT newgroup новая группа, полученная из прежней, сохраняющая порядок, определенный group (дескриптор)

 

Создает новую группу, путем удаления из group процессов с номерами ranks[0] ,...ranks[n-1]. Если n = 0, то newgroup идентична group.

 

Деструктор групп - MPI_Group _free(group)

INOUT group идентификатор группы (дескриптор)

 

Функции доступа к коммуникаторам

Все следующие операции являются локальными.

1. MPI_Comm_size (comm, size)

IN comm коммуникатор (дескриптор)

OUT size количество процессов в группе comm (целое)

 

Эта функция указывает число процессов в коммуникаторе. Для MPI_COMM_WORLD она указывает общее количество доступных процессов.

 

2. MPI_Comm_rank(comm, rank)

IN comm коммуникатор (дескриптор)

OUT rank номер вызывающего процесса в группе comm (целое)

 

Функция MPI_Comm_rank возвращает номер процесса в частной группе коммуникатора. Ее удобно использовать cовместно с MPI_Comm_size.

 

3. MPI_Comm_compare(comm1, comm2, result)

IN comm1 первый коммуникатор (дескриптор)

IN comm2 второй коммуникатор (дескриптор)

OUT result результат (целое)

 

Функция MPI_Comm_compare сравнивает контексты коммуникаторов. Результат MPI_IDENT имеет место тогда и только тогда, когда comm1 и comm2 являются дескрипторами для одного и того же объекта. Результат MPI_CONGRUENT имеет место в том случае, если исходные группы идентичны по компонентам и нумерации; в этом случае коммуникаторы отличаются только контекстом. Результат MPI_SIMILAR имеет место, если члены группы обоих коммуникаторов являются одинаковыми, но порядок их нумерации различен. В противном случае выдается результат MPI_UNEQUAL.

 

Конструкторы коммуникаторов

Ниже перечисленные функции являются коллективными и вызываются всеми процессами в группе, связанной с comm. В MPI для создания нового коммуникатора необходим исходный коммуникатор. Основным коммуникатором для всех MPI коммуникаторов является коммуникатор MPI_COMM_WORLD.

 

1. MPI_Comm_dup(comm, newcomm)

IN comm коммуникатор (дескриптор)

OUT newcomm копия comm (дескриптор)

 

Функция MPI_Comm_dup дублирует существующий коммуникатор comm, возвращает в аргументе newcomm новый коммуникатор с той же группой.

 

2. MPI_Comm_create(comm, group, newcomm)

IN comm коммуникатор (дескриптор)

IN group группа, являющаяся подмножеством группы comm (дескриптор)

OUT newcomm новый коммуникатор (дескриптор)

 

Функция создает новый коммуникатор newcomm с коммуникационной группой, определенной аргументом group и новым контекстом. Из comm в newcomm не передается никакой кэшированной информации. Функция возвращает MPI_COMM_NULL для процессов, не входящих в group. Запрос неверен, если не все аргументы в group имеют одинаковое значение или если group не является подмножеством группы, связанной с comm. Заметим, что запрос должен быть выполнен всеми процессами в comm, даже если они не принадлежат новой группе.

 

3. MPI_Comm_split(comm, color, key, newcomm)

IN comm коммуникатор (дескриптор)

IN color управление созданием подмножества (целое)

IN key управление назначением номеров целое)

OUT newcomm новый коммуникатор (дескриптор)

 

Эта функция делит группу, связанную с comm, на непересекающиеся подгруппы по одной для каждого значения color. Каждая подгруппа содержит все процессы одного цвета. В пределах каждой под группы процессы пронумерованы в порядке, определенном значением аргумента key, со связями, разделенными согласно их номеру в старой группе.

Для каждой подгруппы создается новый коммуникатор и возвращается в аргументе newcomm. Процесс может иметь значение цвета MPI_UNDEFINED, тогда переменная newcomm возвращает значение MPI_COMM_NULL. Это коллективная операция, но каждому процессу разрешается иметь различные значения для color и key.

 

Обращение к MPI_Comm_create (сomm, group, newcomm) эквивалентно обращению к MPI_Comm_split (comm, color, key, newcomm), где все члены group имеют color =0 и key = номеру в group, и все процессы, которые не являются членами group, имеют color = MPI_UNDEFINED.

 

Функция MPI_Comm_split допускает более общее разделение группы на одну или несколько подгрупп с необязательным переупорядочением. Этот запрос используют только интра-коммуникаторы. Значение color должно быть неотрицательно.

Управление группой

Операции управления являются локальными, и их выполнение не требует меж процессного обмена.

 

Функции доступа к группе

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, если процесс не является членом группы (целое)

 

3. MPI_Group_translate_ranks (MPI_Group group1, int n, int *ranks1, MPI_Group group2, int *ranks2)

IN group1 группа1 (дескриптор)

IN n число номеров в массивах ranks1 и ranks2 (целое)

IN ranks1 массив из номеров процессов в группе1

IN group2 группа2 (дескриптор)

OUT ranks2 массив соответствующих номеров процессов в группе2, MPI_UNDEFINED, если соответствие отсутствует.

 

Функция MPI_Group_translate_ranks определяет относительную нумерацию одинаковых процессов в двух различных группах. Например, если известны номера некоторых процессов в MPI_COMM_WORLD, то можно узнать их номера в подмножестве этой группы.

 

4. MPI_Group _compare(group1, group2, result)

group1 первая группа (дескриптор)

group2 вторая группа (дескриптор)

OUT result результат (целое)

Функция MPI_Group_compare сравнивает группы. Если члены группы и их порядок в обеих группах одинаковы, результат будет MPI_IDENT. Если члены группы одинаковы, но порядок различен, то результат будет MPI_SIMILAR. В остальных случаях - MPI_UNEQUAL.

 

Конструкторы групп

Конструкторы создают новые группы на основе существующих групп. Данные операции являются локальными, и различные группы могут быть определены на различных процессах.

 

MPI не имеет механизма для формирования группы с нуля – группа может формироваться только на основе другой, предварительно определенной группы. Базовая группа, на основе которой определены все другие группы, является группой, связанной с коммуникатором MPI_COMM_WORLD (через функцию MPI_COMM_GROUP).

 

1. MPI_Comm_group(MPI_Comm comm, MPI_Group *group)

IN comm коммуникатор (дескриптор)

OUT group группа, соответствующая comm (дескриптор)

 

Функция MPI_Comm_group возвращает в group дескриптор группы из comm.

 

2. MPI_Group_union(MPI_Group group1, MPI_Group group2, MPI_Group *newgroup)

IN group1 первая группа (дескриптор)

IN group2 вторая группа (дескриптор)

OUT newgroup объединенная группа (дескриптор)

 

Объединение (union) – содержит все элементы первой группы (group1) и следующие за ними элементы второй группы (group2), не входящие в первую группу.

 

3. MPI_Group_intersection(MPI_Group group1, MPI_Group group2,MPI_Group *newgroup)

IN group1 первая группа (дескриптор)

IN group2 вторая группа (дескриптор)

OUT newgroup группа, образованная пересечением (дескриптор)

 

Пересечение (intersect) – содержит все элементы group1, которые также находятся в group2 и упорядоченные, как в первой группе.

 

4. MPI_Group_difference(MPI_Group group1, MPI_Group group2,MPI_Group *newgroup)

IN group1 первая группа(дескриптор)

IN group2 вторая группа (дескриптор)

OUT newgroup исключенная группа (дескриптор)

 

Разность (difference) – содержит все элементы group1, которые не находятся в group2.

 

5. MPI_ Group_incl(group, n, ranks, newgroup)

IN group группа (дескриптор)

IN n количество элементов в массиве номеров (и размер newgroup, целое)

IN ranks номера процессов в group, перешедших в новую группу (массив целых)

OUT newgroup новая группа, полученная из прежней, упорядоченная согласно ranks

Cоздает новую группу, которая состоит из n процессов исходной группы group с номерами rank[0],..., rank[n-1]; процесс с номером i в newgroup есть процесс с номером ranks[i] в group. Если n = 0, то newgroup имеет значение MPI_GROUP_EMPTY.

 

 

6. MPI_Group _excl(group, n, ranks, newgroup)

IN group группа (дескриптор)

IN n количество элементов в массиве номеров (целое)

IN ranks массив целочисленных номеров в group, не входящих в newgroup

OUT newgroup новая группа, полученная из прежней, сохраняющая порядок, определенный group (дескриптор)

 

Создает новую группу, путем удаления из group процессов с номерами ranks[0] ,...ranks[n-1]. Если n = 0, то newgroup идентична group.

 

Деструктор групп - MPI_Group _free(group)

INOUT group идентификатор группы (дескриптор)

 

Функции доступа к коммуникаторам

Все следующие операции являются локальными.

1. MPI_Comm_size (comm, size)

IN comm коммуникатор (дескриптор)

OUT size количество процессов в группе comm (целое)

 

Эта функция указывает число процессов в коммуникаторе. Для MPI_COMM_WORLD она указывает общее количество доступных процессов.

 

2. MPI_Comm_rank(comm, rank)

IN comm коммуникатор (дескриптор)

OUT rank номер вызывающего процесса в группе comm (целое)

 

Функция MPI_Comm_rank возвращает номер процесса в частной группе коммуникатора. Ее удобно использовать cовместно с MPI_Comm_size.

 

3. MPI_Comm_compare(comm1, comm2, result)

IN comm1 первый коммуникатор (дескриптор)

IN comm2 второй коммуникатор (дескриптор)

OUT result результат (целое)

 

Функция MPI_Comm_compare сравнивает контексты коммуникаторов. Результат MPI_IDENT имеет место тогда и только тогда, когда comm1 и comm2 являются дескрипторами для одного и того же объекта. Результат MPI_CONGRUENT имеет место в том случае, если исходные группы идентичны по компонентам и нумерации; в этом случае коммуникаторы отличаются только контекстом. Результат MPI_SIMILAR имеет место, если члены группы обоих коммуникаторов являются одинаковыми, но порядок их нумерации различен. В противном случае выдается результат MPI_UNEQUAL.

 

Конструкторы коммуникаторов

Ниже перечисленные функции являются коллективными и вызываются всеми процессами в группе, связанной с comm. В MPI для создания нового коммуникатора необходим исходный коммуникатор. Основным коммуникатором для всех MPI коммуникаторов является коммуникатор MPI_COMM_WORLD.

 

1. MPI_Comm_dup(comm, newcomm)

IN comm коммуникатор (дескриптор)

OUT newcomm копия comm (дескриптор)

 

Функция MPI_Comm_dup дублирует существующий коммуникатор comm, возвращает в аргументе newcomm новый коммуникатор с той же группой.

 

2. MPI_Comm_create(comm, group, newcomm)

IN comm коммуникатор (дескриптор)

IN group группа, являющаяся подмножеством группы comm (дескриптор)

OUT newcomm новый коммуникатор (дескриптор)

 

Функция создает новый коммуникатор newcomm с коммуникационной группой, определенной аргументом group и новым контекстом. Из comm в newcomm не передается никакой кэшированной информации. Функция возвращает MPI_COMM_NULL для процессов, не входящих в group. Запрос неверен, если не все аргументы в group имеют одинаковое значение или если group не является подмножеством группы, связанной с comm. Заметим, что запрос должен быть выполнен всеми процессами в comm, даже если они не принадлежат новой группе.

 

3. MPI_Comm_split(comm, color, key, newcomm)

IN comm коммуникатор (дескриптор)

IN color управление созданием подмножества (целое)

IN key управление назначением номеров целое)

OUT newcomm новый коммуникатор (дескриптор)

 

Эта функция делит группу, связанную с comm, на непересекающиеся подгруппы по одной для каждого значения color. Каждая подгруппа содержит все процессы одного цвета. В пределах каждой под группы процессы пронумерованы в порядке, определенном значением аргумента key, со связями, разделенными согласно их номеру в старой группе.

Для каждой подгруппы создается новый коммуникатор и возвращается в аргументе newcomm. Процесс может иметь значение цвета MPI_UNDEFINED, тогда переменная newcomm возвращает значение MPI_COMM_NULL. Это коллективная операция, но каждому процессу разрешается иметь различные значения для color и key.

 

Обращение к MPI_Comm_create (сomm, group, newcomm) эквивалентно обращению к MPI_Comm_split (comm, color, key, newcomm), где все члены group имеют color =0 и key = номеру в group, и все процессы, которые не являются членами group, имеют color = MPI_UNDEFINED.

 

Функция MPI_Comm_split допускает более общее разделение группы на одну или несколько подгрупп с необязательным переупорядочением. Этот запрос используют только интра-коммуникаторы. Значение color должно быть неотрицательно.

 

  1. Понятие виртуальной топологии MPI, типы топологий. Особенности реализации взаимодействия параллельных процессов с использованием топологических функций MPI.

 

Виртуальная топология определяет отображение номеров процессов в группе на определенную топологию, и наоборот. Для создания виртуальных топологий определены специальные конструкторы, рассматривать которые будем позже.

Топология процессов

Топология – это логическая организация процессов в группе (внутри коммуникатора). Такую логическую организацию процессов имеет еще одно название - “виртуальная топология ”.

Следует различать виртуальную и физическую топологию процессов. Виртуальная топология должна применяться к физическим процессам для организации логической структуры процессов с целью увеличения производительность обменов на данной машине. Описание виртуальной топологии зависит от конкретного приложения и является машинно-независимой.

Общим видом топологии процессов является структура графа. Узлы такого графа представляют процессы, ребра соответствуют связям между процессами. Большая доля всех параллельных приложений использует топологию двумерных массивов. Эта структура полностью определяется количеством процессов по каждой координате (строки и столбцы). Координаты в декартовой системе нумеруются от 0. Например, соотношение между номером процесса в группе и координатами в решетке 2х2 для четырех процессов будет следующим:

coord (0,0): rank 0 сoord (0,1): rank 1

сoord (1,0): rank 2 сoord (1,1): rank 3

 

Конструктор декартовой топологии

1. MPI_Cart_create(MPI_Comm comm_old, int ndims, int *dims, int *periods, int reorder, MPI_Comm *comm_cart)

IN comm_old исходный коммуникатор (дескриптор)

IN ndims размерность создаваемой декартовой решетки (целое)

IN dims массив размера ndims, определяет количество процессов по каждой координате

IN periods массив логических элементов размера ndims, определяет, периодична (true) или нет (false) решетка в каждой размерности

IN reorder нумерация может быть сохранена (false) или переупорядочена (true)

OUT comm_cart коммуникатор новой декартовой топологии (дескриптор)

Функция MPI_Cart_create является коллективной, создает новый коммуникатор для описания декартовой топологии произвольной размерности. По каждой координате устанавливается признак периодичности. Если reorder = false, то номер каждого процесса в новой группе идентичен номеру в старой группе. Иначе функция может переупорядочить процессы (возможно, чтобы обеспечить хорошее наложение виртуальной топологии на физическую систему). Если полная размерность декартовой решетки меньше количества процессов в группе, то некоторые процессы возвращаются с результатом MPI_COMM_NULL. Вызов будет неверным, если он задает решетку большего размера, чем размер группы.

 

2. MPI_Dims_create(int nnodes, int ndims, int *dims)

IN nnodes количество узлов решетки (целое)

IN ndims число размерностей (координат) декартовой решетки (целое)

INOUT dims целочисленный массив размера ndims, определяет количество процессов по каждой координате

Задает количество процессов по каждой размерности (координате). Элементы массива dims описывают декартову решетку координат с числом размерностей ndims и общим количеством узлов nnodes.

Если размерность dims[i] - положительное число, функция не будет изменять число узлов в направлении i; будут изменены только те элементы, для которых dims[i] = 0. Отрицательные значения dims[i] неверны. Также будет неверно, если значение nnodes не кратно произведению dims[i]. Аргумент dims[i], установленный вызывающей программой, будет упорядочен по убыванию. Массив dims удобен для использования в функции MPI_Cart_create в качестве входного. Функция является локальной.

Пример: Массив dims перед вызовом вызов функции, dims после выхода из функции

(0,0) MPI_DIMS_CREATE(6, 2, dims) (3,2)

(0,0) MPI_DIMS_CREATE(7, 2, dims) (7,1)

 

Функции запроса декартовой топологии

1. MPI_Cartdim_get(MPI_Comm comm, int *ndims)

IN comm коммуникатор с декартовой топологией (дескриптор)

OUT ndims число размерностей в декартовой топологии системы (целое)

 

2. MPI_Cart_get(MPI_Comm comm, int maxdims, int *dims, int *periods, int *coords)

IN comm коммуникатор с декартовой топологией (дескриптор)

IN maxdims длина векторов dims, periods и coords (целое)

OUT dims число процессов по каждой декартовой размерности (целочисленный массив)

OUT periods периодичность ( true/ false) для каждой декартовой размерности (массив логических элементов)

OUT coords координаты вызываемых процессов в декартовой системе координат (целочисленный массив)

 

3. int MPI_Cart_rank(MPI_Comm comm, int *coords, int *rank)

IN comm коммуникатор с декартовой топологией (дескриптор)

IN coords целочисленный массив (размера ndims), описывающий декартовы координаты процесса

OUT rank номер указанного процесса (целое)

MPI_Cart_rank переводит логические координаты процессов в их физические номера (номер процесса в группе), которые используются при выполнении обменов.

Для размерности i с periods(i) = true, если координата cords(i) выходит за границу диапазона – coords(i)<0 или coords(i)≥dims(i), она автоматически сдвигается назад к интервалу 0≤coords(i)<dims(i). Выход координат за пределы диапазона неверен для непериодических размерностей.

 

4. int MPI_Cart_coords(MPI_Comm comm, int rank, int maxdims, int *coords)

IN comm коммуникатор с декартовой топологией (дескриптор)

N rank номер процесса внутри группы comm (целое)

IN maxdims длина вектора coord (целое)

OUT coords целочисленный массив (размера ndims), содержащий декартовы координаты указанного процесса (целое)

MPI_Cart_coords используется для перевода номера процесса в группе в логическую координату.

 

5. Координаты декартова сдвига

Если топология это декартова структура, то MPI_SENDRECV часто используется вдоль какой-нибудь координаты, чтобы произвести сдвиг данных. На вход функции MPI_SENDRECV нужно подавать ранг источника для приёма и ранг приёмника для передачи. Вызов функции MPI_Cart_shift определяет эти аргументы.

MPI_Cart_shift(comm, direction, disp, rank_source, rank_dest)

IN comm - коммуникатор с декартовой структурой

IN direction - координата сдвига (integer)

IN disp - смещение (> 0: сдвиг вперёд, < 0: сдвиг назад) (integer)

OUT rank_source - ранг процесса источника (integer)

OUT rank_source - ранг процесса источника (integer)

 

direction определяет координату значение которой изменяется сдвигом. Координаты нумеруются от 0 до ndims-1, где ndims количество размерностей. В зависимости от периодичности декартовой группы по выделенной координате MPI_Cart_shift даёт циклический или конечный сдвиг. В случае конечного сдвига, в rank_source или rank_dest может быть возвращено значение MPI_PROC_NULL, которые отмечают, что источник или приёмник при сдвиге выходят за допустимые пределы.

 

Пример: На основе группы из 8 процессов создали декартову топологию: {2,4}, определим смещение disp =1

1. Решетка процессов не периодичная, direction=0 задает сдвиг по строкам (вдоль столбцов)

0 1 2 3 0 проц. получает от проц. -1 и отправляет проц. 4

1 проц. получает от проц. -1 и отправляет проц. 5 4 5 6 7

 

 

0 ----- -1 rank_source 4 rank_dest

1 ----- -1 5

2 ----- -1 6

3 ----- -1 7

4 ----- 0 -1

5 ----- 1 -1

6 ----- 2 -1

7 ----- 3 -1

2. Решетка процессов периодичная, direction=0 задает сдвиг по строкам (вдоль столбцов)

0 1 2 3 0 проц. получает от проц. 4 и отправляет проц. 4

1 проц. получает от проц. 5 и отправляет проц. 5 4 5 6 7

0 ----- 4 rank_source 4 rank_dest

1 ----- 5 5

2 ----- 6 6

3 ----- 7 7

4 ----- 0 0

5 ----- 1 1

6 ----- 2 2

7 ----- 3 3

3. Решетка процессов не периодичная, direction=1 задает сдвиг по столбцам (вдоль строк)

0 1 2 3 0 проц. получает от проц. -1 и отправляет проц. 1

1 проц. получает от проц. 0 и отправляет проц. 2 4 5 6 7

0 ----- -1 rank_source 1 rank_dest

1 ----- 0 2

2 ----- 1 3

3 ----- -1 7

4 ----- 2 -1

5 ----- -1 5

6 ----- 4 6

7 ----- 6 -1

 

4. Решетка процессов периодичная, direction=1 задает сдвиг по столбцам (вдоль строк)

0 1 2 3 0 проц. получает от проц. 3 и отправляет проц. 1

1 проц. получает от проц. 0 и отправляет проц. 2 4 5 6 7

 

0 ----- 3 rank_source 1 rank_dest

1 ----- 0 2

2 ----- 1 3

3 ----- 2 0

4 ----- 7 5

5 ----- 4 6

6 ----- 5 7

7 ----- 6 4

 

 

Конструктор универсальной (графовой) топологии

int MPI_Graph_create(MPI_Comm comm_old, int nnodes, int *index, int *edges, int reorder, MPI_Comm *comm_graph)

IN comm_old входной коммуникатор (дескриптор)

IN nnodes количество узлов графа (целое)

IN index массив целочисленных значений, описывающий степени вершин

IN edges массив целочисленных значений, описывающий ребра графа

IN reorder номера могут быть переупорядочены ( true) или нет ( false)

OUT comm_graph построенный коммуникатор с графовой топологией (дескриптор)

Функция MPI_Graph_create является коллективной, создает новый коммуникатор для описания графовой топологии. Если reorder = false, то номер каждого процесса в новой группе идентичен его номеру в старой группе. В противном случае функция может переупорядочить процессы. Если количество узлов графа nnodes меньше, чем размер группы коммуникатора, то процессы, не вошедшие в топологию возвращают значение MPI_COMM_NULL. Вызов будет неверным, если определен граф большего размера, чем размер группы исходного коммуникатора.

Структуру графа определяют три параметра: nnodes, index и edges. Nnodes – число узлов графа от 0 до nnodes-1. i-ый элемент массива index хранит общее число соседей первых i вершин графа. Списки соседей вершин 0, 1, ..., nnodes-1 хранятся в последовательности ячеек массива edges. Общее число элементов в index есть nnodes, а общее число элементов в edges равно числу ребер графа.

 

Функции запроса топологии графа

Следующие две функции: MPI_Graphdims_get и MPI_Graph_get через коммуникатор возвращают информацию о топологии, которая была создана функцией MPI_Graph_create.

1. int MPI_Graphdims_get(MPI_Comm comm, int *nnodes, int *nedges)

IN comm коммуникатор группы с графовой топологией (дескриптор)

OUT nnodes число вершин графа (целое, равно числу процессов в группе)

OUT nedges число ребер графа (целое)

 

Полученные значения массивов index и edges может быть использована для корректного определения размера векторов index и edges в функции MPI_Graph_get.

 

2. int MPI_Graph_get(MPI_Comm comm, int maxindex, int maxedges, int *index, int *edges)

IN comm коммуникатор с графовой топологией (дескриптор)

IN maxindex длина вектора index (целое)

IN maxedges длина вектора edges (целое)

OUT index целочисленный массив, содержащий структуру графа (подробнее в описании функции MPI_Graph_greate)

OUT edges целочисленный массив, содержащий структуру графа

 

3. int MPI_Graph_neighbors_count(MPI_Comm comm, int rank, int *nneighbors)

IN comm коммуникатор с графовой топологией (дескриптор)

IN rank номер процесса в группе comm (целое)

OUT nneighbors номера процессов, являющихся соседними указанному процессу (целочисленный массив)

 

4. int MPI_Graph_neighbors(MPI_Comm comm, int rank, int maxneighbors, int *neighbors)

IN comm коммуникатор с графовой топологией (дескриптор)

IN rank номер процесса в группе comm (целое)

IN maxneighbors размер массива neighbors (целое)

OUT neighbors номера процессов, соседних данному (целочисленный массив)

 

Функция запроса типа топологии

Если топология была определена одной из вышеупомянутых функций, то информация об этой топологии может быть получена с помощью функций запроса. Все они являются локальными вызовами.

int MPI_Topo_test(MPI_Comm comm, int *status)

IN comm коммуникатор (дескриптор)

OUT status тип топологии коммуникатора comm (альтернатива)

 

MPI_Topo_test возвращает тип топологии, которую определяет коммуникатор.Выходное значение status имеет одно из следующих значений:

MPI_GRAPH топология графа

MPI_CART декартова топология

MPI_UNDEFINED топология не определена

 

  1. Технология программирования OpenMP. Основные конструкции OpenMP С реализации.

 







Дата добавления: 2015-08-12; просмотров: 2609. Нарушение авторских прав


Рекомендуемые страницы:


Studopedia.info - Студопедия - 2014-2020 год . (0.162 сек.) русская версия | украинская версия