Ответ 1
В картине написано более тысячи слов, так что вот несколько художественных фотографий ASCII:
rank send buf recv buf
---- -------- --------
0 a,b,c MPI_Allgather a,b,c,A,B,C,#,@,%
1 A,B,C ----------------> a,b,c,A,B,C,#,@,%
2 #,@,% a,b,c,A,B,C,#,@,%
Это обычный регулярный MPI_Gather
, только в этом случае все процессы получают куски данных, т.е. операция не имеет значения root.
rank send buf recv buf
---- -------- --------
0 a,b,c MPI_Alltoall a,A,#
1 A,B,C ----------------> b,B,@
2 #,@,% c,C,%
(a more elaborate case with two elements per process)
rank send buf recv buf
---- -------- --------
0 a,b,c,d,e,f MPI_Alltoall a,b,A,B,#,@
1 A,B,C,D,E,F ----------------> c,d,C,D,%,$
2 #,@,%,$,&,* e,f,E,F,&,*
(выглядит лучше, если каждый элемент окрашен раном, который отправляет его, но...)
MPI_Alltoall
работает как объединенный MPI_Scatter
и MPI_Gather
- буфер отправки в каждом процессе разбивается как на MPI_Scatter
, а затем каждый столбец кусков собирается соответствующим процессом, чей ранг соответствует числу кусок колонка. MPI_Alltoall
также можно рассматривать как глобальную операцию транспонирования, действующую на куски данных.
Есть ли случай, когда две операции взаимозаменяемы? Чтобы правильно ответить на этот вопрос, нужно просто проанализировать размеры данных в буфере отправки и данных в буфере приема:
operation send buf size recv buf size
--------- ------------- -------------
MPI_Allgather sendcnt n_procs * sendcnt
MPI_Alltoall n_procs * sendcnt n_procs * sendcnt
Размер буфера приема на самом деле n_procs * recvcnt
, но MPI указывает, что количество отправленных базовых элементов должно быть равно количеству принятых базовых элементов, следовательно, если один и тот же тип данных MPI используется в обеих частях отправки и получения MPI_All...
, то recvcnt
должен быть равен sendcnt
.
Сразу видно, что при одном и том же размере полученных данных количество данных, отправляемых каждым процессом, отличается. Для того чтобы обе операции были равны, одним из необходимых условий является то, что размеры отправленных буферов в обоих случаях равны, т.е. n_procs * sendcnt == sendcnt
, что возможно только в том случае, если n_procs == 1
, т.е. если есть только один процесс или если sendcnt == 0
, т.е. никакие данные не отправляются вообще. Следовательно, практически нет практического случая, когда обе операции действительно взаимозаменяемы. Но можно моделировать MPI_Allgather
с помощью MPI_Alltoall
, повторяя n_procs
раза те же данные в буфере отправки (как уже было отмечено Тайлером Гиллом). Вот действие MPI_Allgather
с одноэлементными буферами отправки:
rank send buf recv buf
---- -------- --------
0 a MPI_Allgather a,A,#
1 A ----------------> a,A,#
2 # a,A,#
И здесь то же самое реализовано с MPI_Alltoall
:
rank send buf recv buf
---- -------- --------
0 a,a,a MPI_Alltoall a,A,#
1 A,A,A ----------------> a,A,#
2 #,#,# a,A,#
Реверс невозможен - в общем случае нельзя моделировать действие MPI_Alltoall
с MPI_Allgather
.