Description
Problem
RMA absolutely did the right thing with MPI_Aint
size and displacement arguments.
In C, it is no problem to pass 32b integers to these arguments when AINT is 64b, because C type promotion rules just work.
In Fortran, I cannot do this, because an integer literal is not compatible with an AINT argument. I find it tedious to have to declare a variable just for this, or to explicitly cast with integer(100,MPI_ADDRESS_KIND)
.
Fortran
! USE mpi_f08
! MPI_Win_allocate(size, disp_unit, info, comm, baseptr, win, ierror)
! USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_PTR
! INTEGER(KIND=MPI_ADDRESS_KIND), INTENT(IN) :: size
! INTEGER, INTENT(IN) :: disp_unit
! TYPE(MPI_Info), INTENT(IN) :: info
! TYPE(MPI_Comm), INTENT(IN) :: comm
! TYPE(C_PTR), INTENT(OUT) :: baseptr
! TYPE(MPI_Win), INTENT(OUT) :: win
! INTEGER, OPTIONAL, INTENT(OUT) :: ierror
program main
use iso_fortran_env
use mpi_f08
implicit none
integer(kind=MPI_ADDRESS_KIND) :: as = 100
type(c_ptr) :: XA
type(MPI_Win) :: WA
TYPE(MPI_Comm) :: comm = MPI_COMM_WORLD
call MPI_Win_allocate(as, 1, MPI_INFO_NULL, comm, XA, WA)
call MPI_Win_allocate(100, 1, MPI_INFO_NULL, comm, XA, WA)
end program main
% mpifort y.F90
y.F90:20:60:
20 | call MPI_Win_allocate(100, 1, MPI_INFO_NULL, comm, XA, WA)
| 1
Error: There is no specific subroutine for the generic 'mpi_win_allocate' at (1)
C
#include <mpi.h>
int main(void)
{
MPI_Aint as = 100;
int * XA;
MPI_Win WA;
MPI_Win_allocate(as, 1, MPI_INFO_NULL, MPI_COMM_WORLD, XA, &WA);
MPI_Win_allocate(100, 1, MPI_INFO_NULL, MPI_COMM_WORLD, XA, &WA);
}
% mpicc y.c && echo SUCCESS
SUCCESS
Proposal
Use Fortran polymorphism and add subroutine declarations for default integer arguments where appropriate.
Changes to the Text
Add the following interfaces.
The rule here is: for all INTENT(IN)
instances of INTEGER(KIND=MPI_ADDRESS_KIND)
that describe a count-like argument (size or displacement), add a default integer interface.
Obviously, there are cases where size and displacement need to larger than INTEGER
but obviously the programmer is going to have to use an AINT there, so there is no potential for misuse. Any time the argument is an AINT, the proper interface will be used. Only when the argument fits into an INTEGER
will that interface be used.
MPI_Alloc_mem
INTERFACE MPI_ALLOC_MEM
SUBROUTINE MPI_ALLOC_MEM_I(SIZE, INFO, BASEPTR, IERROR)
IMPORT :: MPI_ADDRESS_KIND
INTEGER, INTENT(IN) :: SIZE
TYPE(MPI_Info), INTENT(IN) :: info
INTEGER(KIND=MPI_ADDRESS_KIND), INTENT(OUT) :: BASEPTR
INTEGER, OPTIONAL, INTENT(OUT) :: IERROR
END SUBROUTINE
SUBROUTINE MPI_ALLOC_MEM_CPTR_I(SIZE, INFO, BASEPTR, IERROR)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_PTR
INTEGER, INTENT(IN) :: SIZE
TYPE(MPI_Info), INTENT(IN) :: info
TYPE(C_PTR), INTENT(OUT) :: BASEPTR
INTEGER, OPTIONAL, INTENT(OUT) :: IERROR
END SUBROUTINE
END INTERFACE
MPI_Win_create
INTERFACE MPI_WIN_CREATE
SUBROUTINE MPI_Win_create_I(base, size, disp_unit, info, comm, win, ierror)
TYPE(*), DIMENSION(..), ASYNCHRONOUS, INTENT(IN) :: base
INTEGER INTENT(IN) :: size, disp_unit
TYPE(MPI_Info), INTENT(IN) :: info
TYPE(MPI_Comm), INTENT(IN) :: comm
TYPE(MPI_Win), INTENT(OUT) :: win
INTEGER, OPTIONAL, INTENT(OUT) :: ierror
END SUBROUTINE
END INTERFACE
MPI_Win_allocate
INTERFACE MPI_WIN_ALLOCATE
SUBROUTINE MPI_WIN_ALLOCATE_I(SIZE, DISP_UNIT, INFO, COMM, BASEPTR, &
WIN, IERROR)
IMPORT :: MPI_ADDRESS_KIND
INTEGER INTENT(IN) :: size, disp_unit
TYPE(MPI_Info), INTENT(IN) :: info
TYPE(MPI_Comm), INTENT(IN) :: comm
TYPE(MPI_Win), INTENT(OUT) :: win
INTEGER(KIND=MPI_ADDRESS_KIND), INTENT(OUT) :: BASEPTR
INTEGER, OPTIONAL, INTENT(OUT) :: ierror
END SUBROUTINE
SUBROUTINE MPI_WIN_ALLOCATE_CPTR_I(SIZE, DISP_UNIT, INFO, COMM, BASEPTR, &
WIN, IERROR)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_PTR
INTEGER, INTENT(IN) :: SIZE, DISP_UNIT
TYPE(MPI_Info), INTENT(IN) :: info
TYPE(MPI_Comm), INTENT(IN) :: comm
TYPE(MPI_Win), INTENT(OUT) :: win
TYPE(C_PTR), INTENT(OUT) :: BASEPTR
INTEGER, OPTIONAL, INTENT(OUT) :: IERROR
END SUBROUTINE
END INTERFACE
MPI_Win_allocate_shared
INTERFACE MPI_WIN_ALLOCATE_SHARED
SUBROUTINE MPI_WIN_ALLOCATE_SHARED_I(SIZE, DISP_UNIT, INFO, COMM, &
BASEPTR, WIN, IERROR)
IMPORT :: MPI_ADDRESS_KIND
INTEGER, INTENT(IN) :: SIZE, DISP_UNIT
TYPE(MPI_Info), INTENT(IN) :: info
TYPE(MPI_Comm), INTENT(IN) :: comm
TYPE(MPI_Win), INTENT(OUT) :: win
TYPE(C_PTR), INTENT(OUT) :: BASEPTR
INTEGER, OPTIONAL, INTENT(OUT) :: IERROR
END SUBROUTINE
SUBROUTINE MPI_WIN_ALLOCATE_SHARED_CPTR_I(SIZE, DISP_UNIT, INFO, COMM, &
BASEPTR, WIN, IERROR)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_PTR
INTEGER, INTENT(IN) :: SIZE, DISP_UNIT
TYPE(MPI_Info), INTENT(IN) :: info
TYPE(MPI_Comm), INTENT(IN) :: comm
TYPE(MPI_Win), INTENT(OUT) :: win
TYPE(C_PTR), INTENT(OUT) :: BASEPTR
INTEGER, OPTIONAL, INTENT(OUT) :: IERROR
END SUBROUTINE
END INTERFACE
MPI_Win_attach
INTERFACE MPI_WIN_ATTACH
SUBROUTINE MPI_WIN_ATTACH_I(WIN, BASE, SIZE, IERROR)
TYPE(MPI_Win), INTENT(IN) :: WIN
TYPE(*), DIMENSION(..), ASYNCHRONOUS :: BASE
INTEGER, INTENT(IN) :: SIZE
INTEGER, OPTIONAL, INTENT(OUT) :: IERROR
END SUBROUTINE
SUBROUTINE MPI_WIN_ATTACH_I(WIN, BASE, SIZE, IERROR)
TYPE(MPI_Win), INTENT(IN) :: win
<type> :: BASE(*)
INTEGER, INTENT(IN) :: SIZE
INTEGER, OPTIONAL, INTENT(OUT) :: IERROR
END SUBROUTINE
END INTERFACE
MPI_Put
INTERFACE MPI_PUT
SUBROUTINE MPI_Put_I(origin_addr, origin_count, origin_datatype, &
target_rank, target_disp, target_count, target_datatype, win, ierror)
TYPE(*), DIMENSION(..), INTENT(IN), ASYNCHRONOUS :: origin_addr
INTEGER, INTENT(IN) :: origin_count, target_rank, target_disp, target_count
TYPE(MPI_Datatype), INTENT(IN) :: origin_datatype, target_datatype
TYPE(MPI_Win), INTENT(IN) :: win
INTEGER, OPTIONAL, INTENT(OUT) :: ierror
END SUBROUTINE
END INTERFACE
And so forth for all other RMA communication operations where TARGET_DISP
is INTEGER(KIND=MPI_ADDRESS_KIND)
.
Impact on Implementations
Fortran 2008 modules in MPI implementation will need to add these interfaces. One hopes the interfaces will be automatically generated, such that the effort required here is minimal.
Impact on Users
This makes RMA easy to use because applications can call RMA functions with integer literals and default integer arguments, rather than having to do explicit casting or create variables just to hold integers in the right type.
This also reduces the mental overhead of switching from C/C++ to Fortran, because no overloads are required in C/C++ due to the way integer casting works (and because scalars are passed by value rather than reference).
References and Pull Requests
No pull request. This can be automatically generated by someone who understands who the interface generation stuff works.
Metadata
Metadata
Labels
Type
Projects
Status