Параллельное программирование: Учебное пособие, страница 116

MPI_Reduce_scatter сначала выполняет поэлементное приведение на векторе, имеющем размер равный  элементов в посылающем буфере, которое определено буфером sendbuf, числом и типом данных его элементов. Затем, вектор результата разбивается на n непересекающиеся сегменты, где n – число членов в группе. Сегмент i содержит  recvcounts(i) элементов. i-тый сегмент посылается i-тому процессу и сохраняется в буфере приема recvbuf с соответствующим recvcounts(i) числом и типом данныхdatatype.

Функционально MPI_REDUCE_SCATTER эквивалентна выполнению двух процедур: MPI_REDUCE, которая подсчитывает, например, сумму и размещает ее на элементахсегмента recvcounts(i), и затем MPI_SCATTERV, в которой передающий буфер sendcounts приравнивается к приемному буферу recvcounts.

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

Подпрограмма MPI_Allreduce собирает данные от всех процессов и сохраняет результат операции приведения в результирующем буфере каждого процесса:

int MPI_Allreduce(void *sendbuf, void *rcvbuf,

int count, MPI_Datatype datatype, MPI_Op op,

MPI_Commcomm)

Ее входные параметры:

·  sendbuf — начальный адрес буфера передачи;

·  count — количество элементов в буфере передачи;

·  datatype — тип передаваемых данных;

·  ор — операция приведения;

·  comm — коммуникатор.

Рисунок 6.6. Схема взаимодействия в MPI_Reduce_scatter

Выходным параметром является стартовый адрес буфера приема rcvbuf. При аварийном завершении подпрограмма может возвращать код ошибки MPI_ERR_OP (некорректная операция). Это происходит, если применяется операция, которая не является предопределенной и которая не создана предшествующим вызовом подпрограммы MPI_Op_create.

Операции сканирования (частичной редукции) выполняются с помощью вызова подпрограммы MPI_Scan:

int MPI_Scan(void *sendbuf, void *rcvbuf, int count,

MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)

Ее входные параметры:

·  sendbuf — начальный адрес буфера передачи;

·  count — количество элементов во входном буфере;

·  datatype — тип данных во входном буфере;

·  ор — операция;

·  comm — коммуникатор.

Выходным параметром является стартовый адрес буфера приема rcvbuf. Схема распределения данных при выполнении операции сканирования приведена на рис. 6.7.


Рисунок 6.7. Операция сканирования

В подпрограмме MPI_Reduce можно использовать только предопределенные типы MPI. Все операции являются ассоциативными и коммутативными (т. е. операнды могут по-разному группироваться, а их порядок не имеет значения). Подпрограмма MPI_Scan похожа на подпрограмму MPI_Allreduce в том отношении, что каждая задача получает результирующий массив. Отличие состоит в том, что содержимое массива-результата в задаче iявляется результатом выполнения операции над массивами из задач с номерами от 0 до i включительно.

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

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

Текст 6.2. Использование операции редукции

#include "mpi.h"

#include <stdio.h>

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

{

int myrank, i;

int count = 5, root = 1;

MPI_Group MPI_GROUP_WORLD, subgroup;   /* Объявление групп */

intranks[4] = {1, 3, 5, 7};       /* Задание рангов для группы */

MPI_Commsubcomm;      /* Объявление имени коммуникатора группы */

intsendbuf[5] = {1, 2, 3, 4, 5};  /* Объявление буферов */

intrecvbuf[5];                    /* передачи и приема    */

MPI_Init(&argc, &argv);                           /* Инициализация MPI */

/* Обеспечиваем доступ к группе MPI_GROUP_WORLD, связывая */

/*  ее с глобальным коммкникатором MPI_COMM_WORLD  */