Студопедия — Пример. Функция MPI_Reduce с операцией MPI_SUM
Студопедия Главная Случайная страница Обратная связь

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

Пример. Функция 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 коммуникаторов является коммуникатор







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



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

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

Практические расчеты на срез и смятие При изучении темы обратите внимание на основные расчетные предпосылки и условности расчета...

Функция спроса населения на данный товар Функция спроса населения на данный товар: Qd=7-Р. Функция предложения: Qs= -5+2Р,где...

Трамадол (Маброн, Плазадол, Трамал, Трамалин) Групповая принадлежность · Наркотический анальгетик со смешанным механизмом действия, агонист опиоидных рецепторов...

Мелоксикам (Мовалис) Групповая принадлежность · Нестероидное противовоспалительное средство, преимущественно селективный обратимый ингибитор циклооксигеназы (ЦОГ-2)...

Менадиона натрия бисульфит (Викасол) Групповая принадлежность •Синтетический аналог витамина K, жирорастворимый, коагулянт...

Тема: Кинематика поступательного и вращательного движения. 1. Твердое тело начинает вращаться вокруг оси Z с угловой скоростью, проекция которой изменяется со временем 1. Твердое тело начинает вращаться вокруг оси Z с угловой скоростью...

Условия приобретения статуса индивидуального предпринимателя. В соответствии с п. 1 ст. 23 ГК РФ гражданин вправе заниматься предпринимательской деятельностью без образования юридического лица с момента государственной регистрации в качестве индивидуального предпринимателя. Каковы же условия такой регистрации и...

Седалищно-прямокишечная ямка Седалищно-прямокишечная (анальная) ямка, fossa ischiorectalis (ischioanalis) – это парное углубление в области промежности, находящееся по бокам от конечного отдела прямой кишки и седалищных бугров, заполненное жировой клетчаткой, сосудами, нервами и...

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