Skip to content

Fortran: MPI RMA integer interfaces for AINT arguments #528

Open
@jeffhammond

Description

@jeffhammond

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

Assignees

Labels

chap-rmaRMA Chapter Committeempi-6For inclusion in the MPI 5.1 or 6.0 standardwg-fortranFortran Working Groupwg-languagesLanguages Working Groupwg-rmaRMA Working Group

Type

No type

Projects

Status

To Do

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions