When will you use different counts or types for sending and receiving processes?
Many procedures in MPI that describe both sending and receiving - MPI_Sendrecv, MPI_Scatter, etc., contain arguments for counts and types for sending and receiving. For example, in Fortran the signature for MPI_Scatter is:
MPI_SCATTER(SENDBUF, SENDCOUNT, SENDTYPE,
RECVBUF, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR)
If the amount of data sent should be the same as the amount received, why is it necessary? Doesn't that just introduce the possibility of inconsistency?
What is the use case when different types / types are needed?
source to share
MPI requires the send and receive processes to agree on data type and quantity (sort of, for a recipient a point-to-point link may request more than it has sent). But MPI data types also describe the layout of data in memory, and that's a very common reason why you need to use different types for sender and receiver.
You are asking about Scatter and Fortran in particular, so let's take a look at this case. Let us consider the scattering of a matrix size*n
by rows for different processes
|---n---| ---
0 0 0 0 |
a = 1 1 1 1 size
2 2 2 2 |
---
Thus, what rank 0 gets [0 0 0 0]
, rank 1 gets [1 1 1 1]
, etc.
In Fortran, they are not contiguous in memory; so to describe the string you will need to use MPI_Type_vector
:
call MPI_Type_vector(n, 1, size, MPI_REAL, row_type, ierr)
This describes n reales, but with each size-separated number in between.
On the other hand, if the get process just takes this data into the 1st array:
real, dimension(n) :: b
Then it cannot use this type to describe data; b
not enough space to store n
reals, each with a space in size
between! He wants to receive data in the same way as n * MPI_REAL
. This mismatch will be the same in C if you need to send columns of data.
And so this is a common reason for specifying the type (and therefore counting) data in different ways; for the diffuser, the data must be described with a data type that includes the layout of a larger data structure containing the values to be sent; but the diffuser can receive data into a different data structure with a different layout.
A working simple example follows.
program scatterdemo
use mpi
implicit none
real, allocatable, dimension(:,:) :: a
real, allocatable, dimension(:) :: b
integer :: ierr, rank, comsize
integer, parameter :: n=4
integer :: i
integer :: row_type, row_type_sized, real_size
integer(kind=MPI_ADDRESS_KIND) :: lb=0, extent
call MPI_Init(ierr)
call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)
call MPI_Comm_size(MPI_COMM_WORLD, comsize, ierr)
if (rank == 0) then
allocate( a(comsize, n) )
do i=1,comsize
a(i,:) = i-1
enddo
endif
allocate( b(n) )
call MPI_Type_size(MPI_REAL, real_size, ierr)
call MPI_Type_vector(n, 1, comsize, MPI_REAL, row_type, ierr)
extent = real_size*1
call MPI_Type_create_resized(row_type, lb, extent, row_type_sized, ierr)
call MPI_Type_commit(row_type_sized, ierr)
call MPI_Scatter(a, 1, row_type_sized, b, n, MPI_REAL, 0, MPI_COMM_WORLD, ierr)
print *, rank, b
if (rank == 0) deallocate (a)
deallocate(b)
call MPI_Finalize(ierr)
end program scatterdemo
and running it with six processors gives
$ mpirun -np 6 ./scatter
0 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00
3 3.000000 3.000000 3.000000 3.000000
1 1.000000 1.000000 1.000000 1.000000
5 5.000000 5.000000 5.000000 5.000000
2 2.000000 2.000000 2.000000 2.000000
4 4.000000 4.000000 4.000000 4.000000
source to share
When you use MPI-based types, you can view the array as n
elements of some basic numeric type, as well as one or more elements of some MPI-based type. In this case, not only the counters, but also the data types may differ, although they correspond to the same buffer.
On the other hand, it does not depend on the number of processes in the communicator. The size of the communicator is always implicit, and you do not enter it directly anywhere when calling the collective.
source to share