Часто бывает полезным в операции put
совместить данные,
перемещаемые в процесс-адресат, с данными которые ему принадлежат, вместо
того, чтобы выполнять замещение этих данных в процессе-инициаторе. Это
позволяет, к примеру, произвести накопление суммы, заставляя все
участвующие процессы добавлять свой вклад в переменную для суммирования,
расположенную в памяти одного процесса.
MPI_ACCUMULATE(origin_addr, origin_count, origin_datatype,
target_rank, target_disp, target_count,
target_datatype, op, win)
IN | origin_addr |
начальный адрес буфера (выбор) | |
IN | origin_count |
число записей в буфере инициатора (неотрицательное целое) | |
IN | origin_datatype |
тип данных каждой записи в буфере (дескриптор) | |
IN | target_rank |
ранг адресата (неотрицательное целое) | |
IN | target_disp |
смещение от начала окна до буфера адресата (неотрицательное целое) | |
IN | target_count |
число записей в буфере адресата (неотрицательное целое) | |
IN | target_datatype |
тип данных каждой записи в буфере адресата (дескриптор) | |
IN | op |
уменьшающая операция (дескриптор) | |
IN | win |
оконный объект (дескриптор) |
int MPI_Accumulate(void *origin_addr, int origin_count,
MPI_Datatype origin_datatype, int target_rank,
MPI_Aint target_disp, int target_count,
MPI_Datatype target_datatype,
MPI_Op op, MPI_Win win)
MPI_ACCUMULATE(ORIGIN_ADDR, ORIGIN_COUNT, ORIGIN_DATATYPE,
TARGET_RANK, TARGET_DISP, TARGET_COUNT,
TARGET_DATATYPE, OP, WIN, IERROR)
<type> ORIGIN_ADDR(*)
INTEGER(KIND=MPI_ADDRESS_KIND) TARGET_DISP
INTEGER ORIGIN_COUNT, ORIGIN_DATATYPE,TARGET_RANK,
TARGET_COUNT, TARGET_DATATYPE, OP, WIN, IERROR
void MPI::Win::Accumulate(const void* origin_addr, int origin_count,
const MPI::Datatype& origin_datatype,
int target_rank, MPI::Aint target_disp,
int target_count,
const MPI::Datatype& target_datatype,
const MPI::Op& op) const
Данная функция накапливает содержимое буфера инициатора (который определяется
параметрами origin_addr
, origin_datatype
и origin_count
) в
буфере, определенном аргументами
target_count
и
target_datatype
,
по смещению target_disp
в окне, определенном при помощи
target_rank
и win
, используя операцию op
.
Функция похожа на MPI_PUT
за исключением того, что данные
объединяются в области адресата вместо их перезаписи.
Может использоваться любая из операций, определенных для
MPI_REDUCE
. Функции, определенные пользователем, использоваться не
могут. Например, если op
это MPI_SUM
, каждый элемент
буфера инициатора прибавляется к соответствующему элементу в буфере
адресата, замещая предыдущее значение в буфере адресата.
Все аргументы должны иметь либо предопределенный тип данных, либо быть
производным типом данных, все базовые компоненты которого являются такими
же предопределенными типами данных. Аргументы как инициатора, так и
адресата должны быть производными от таких же предопределенных типов.
Операция op
применяется к элементам этого предопределенного типа.
Параметр target_datatype
не может определять перекрывающиеся записи, и
буфер адресата должен помещаться в окне адресата.
Определяется новая предопределенная операция
MPI_REPLACE
. Она соответствует
ассоциативной функции ; это значит, что данное значение в
памяти адресата замещается значением, взятым из памяти инициатора.
Совет разработчикам:
В простейшем случае MPI_PUT
- это особый случай MPI_ACCUMULATE
с операцией MPI_REPLACE
. Отметим, тем не менее, что
MPI_PUT
и MPI_ACCUMULATE
имеют разные ограничения на
конкурентные обновления. []
Пример 4.3
Мы хотим вычислить
. Массивы A
,
B
и map
распределены одинаковым образом. Напишем простую
версию.
SUBROUTINE SUM(A, B, map, m, comm, p)
USE MPI
INTEGER m, map(m), comm, p, sizeofreal, win, ierr
REAL A(m), B(m)
CALL MPI_TYPE_EXTENT(MPI_REAL, sizeofreal, ierr)
CALL MPI_WIN_CREATE(B, m*sizeofreal, sizeofreal, MPI_INFO_NULL, &
comm, win, ierr)
CALL MPI_WIN_FENCE(0, win, ierr)
DO i=1,m
j = map(i)/p
k = MOD(map(i),p)
CALL MPI_ACCUMULATE(A(i), 1, MPI_REAL, j, k, 1, MPI_REAL, &
MPI_SUM, win, ierr)
END DO
CALL MPI_WIN_FENCE(0, win, ierr)
CALL MPI_WIN_FREE(win, ierr)
RETURN
END
Этот код идентичен коду в примере 6.2 за исключением того, что вызов
get
был заменен на вызов accumulate
. (Заметим, что если
mapLocal
возвращает то, что получает, тогда код вычисляет
B=A(map^-1)
, что есть обратное присваивание по отношению к
вычисленному в предыдущем примере.) Схожим образом в примере 6.1 мы
можем заменить вызов get
вызовом accumulate
, таким образом,
выполняя вычисления только с одним взаимодействием между любыми двумя
процессами.