I am very new to MPI programming (like 3 days old). I am now dealing with MPI_ALLREDUCE
and MPI_REDUCE
.
The code below takes a value n
and the task of every process is to add 1 to the variable mypartialsum
for n/num_procs
times, where num_procs
is the number of processes. After the reduction the values of mypartialsum
are gathered in sum
and the final result is sum=n
.
The code seems to work fine if n<1d10
, but for n>=1d10
I get the wrong result.
For example, if I run the code with n=1d10
the value of sum is 1410065408
, while it is correct for n=1d9
. What I am missing? I suspect it could be something with the kind of the variables, but after looking on the internet it is not clear to me what the problem is.
program test
use mpi
IMPLICIT NONE
!include 'mpif.h'
integer:: ierr, num_procs, my_id, status(MPI_STATUS_SIZE), sender(MPI_STATUS_SIZE), root, rank
integer:: i!, n
integer, parameter :: MyLongIntType = selected_int_kind (12)
integer(kind=MyLongIntType):: n
!real:: sum=0., partialsum=0., mypartialsum=0.
integer(kind=MyLongIntType):: sum=0, partialsum=0, mypartialsum=0
real:: starttime, endtime
root=0
call MPI_INIT ( ierr )
call MPI_COMM_RANK (MPI_COMM_WORLD, my_id, ierr)
call MPI_COMM_SIZE (MPI_COMM_WORLD, num_procs, ierr)
starttime = MPI_WTIME()
if (my_id .eq. root) then
print*, "Running in process 0."
print*, "total numeber of process is", num_procs
n=int8(1d10)!1000000000
endif
call MPI_BCAST(n, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
!print*, "running process", my_id
mypartialsum=0.
do i = my_id+1, n, num_procs
mypartialsum=mypartialsum+int(1)
enddo
partialsum=mypartialsum
print*, "Running process", my_id, "Partial sum is ", partialsum
call MPI_REDUCE(partialsum, sum, 1, MPI_INTEGER, MPI_SUM, ROOT, MPI_COMM_WORLD, ierr)
!call MPI_ALLREDUCE(partialsum, sum, 1, MPI_INTEGER, MPI_SUM, MPI_COMM_WORLD, ierr)
endtime = MPI_WTIME()
if (my_id .eq. 0) then
print*, "sum is", sum, "time spent processing", endtime-starttime
! else if (my_id .gt. 0) then
! print*, "sum on process", my_id, "is", sum , "time spent processing is", endtime-starttime
endif
call MPI_FINALIZE ( ierr )
end program
You are telling MPI_Reduce
that the type being summed is MPI_INTEGER
. However, MPI_INTEGER
corresponds to the default integer kind in Fortran. You have to provide the correct MPI type that corresponds to the selected_int_kind (12)
type.
One of the possible ways, specifically for kinds resulting from selected_integer_kind
is the MPI_Type_create_f90_integer(r, newtype, ierror)
subroutine.
So something like call MPI_Type_create_f90_integer(12, MyLongIntMPIType, ierror)
.
There are other alternatives, like using fixed memory storage kinds like integer(int64)
and the MPI_INTEGER8
MPI type originally developed for the non-standard integer*8
.
See also Additional Support for Fortran Numeric Intrinsic Types
It also contains this important advice to users:
The datatypes returned by the above functions are predefined datatypes. They cannot be freed; they do not need to be committed; they can be used with predefined reduction operations.
which makes it simple to use the returned type in MPI_Reduce()
with MPI_SUM
.