mpi-forum / mpi-issues

Tickets for the MPI Forum
http://www.mpi-forum.org/
67 stars 8 forks source link

must integer constants be the same in C and Fortran? #713

Closed jeffhammond closed 1 year ago

jeffhammond commented 1 year ago

Problem

Handles and buffer address constants are necessarily different between C and Fortran in some cases.

Are the integer constants allowed to be different or not? For example, is MPI_ANY_TAG from mpi.h required to match the Fortran module parameters?

Proposal

Say this explicitly, for whatever the answer is.

Changes to the Text

Impact on Implementations

I think everybody defines the integer constants the same in C and Fortran today, but e.g. VAPAA can't necessarily do this.

Impact on Users

I don't think anybody will notice this although I can write code that does.

References and Pull Requests

jeffhammond commented 1 year ago

@RolfRabenseifner do you have any thoughts on this one? Seems obvious, but I can't find a conclusive statement about it.

besnardjb commented 1 year ago

I would be inclined to say they can be different.

It might be a controversial discussion but I'm very curious about feedback. If Fortran was considered as external binding (facilitated by ABI and as demonstrated by VAPAA) this would be simpler, the standard would shrink, and all calls would go through the same path (good for PMPI, QMPI, debug) and we would not question the constant values.

For the "simpler" part, I'm particularly thinking of “MPIIO Split collectives” (14.4.5) leading to this due to Fortran :

Split collective routines must specify a buffer in both the begin and end routines. By specifying the buffer that receives data in the end routine, we can avoid the problems described in “A Problem with Code Movements and Register Optimization,” Section 19.1.17, but not all of the problems, such as those described in Sections 19.1.12, 19.1.13, and 19.1.16.

and unfolding to this 19.1.17 (and other 19.1.X) which are honestly compiler-level (and maybe outdated; sorry not a Fortran specialist) discussions:

If a variable is local to a Fortran subroutine (i.e., not in a module or a COMMON block), the compiler will assume that it cannot be modified by a called subroutine unless it is an actual argument of the call. In the most common linkage convention, the subroutine is expected to save and restore certain registers. Thus, the optimizer will assume that a register which held a valid copy of such a variable before the call will still hold a valid copy on return.

Note: "Linkage" convention (calling I suppose).

There are certainly strong historical reasons and decisive arguments for/against all this but I'm wondering:

RolfRabenseifner commented 1 year ago

@jeffhammond and @besnardjb In MPI-4.0 (and the text exists since MPI-2.1) , there is Section 19.3 Language Interoperability with sub-section 19.3.9 Constants MPI constants have the same value in all languages, unless specified otherwise. This does not apply to constant handles (MPI_INT, MPI_COMM_WORLD, MPI_ERRORS_RETURN, MPI_SUM, etc.) These handles need to be converted, as explained in Section 19.3.4. Constants that specify maximum lengths of strings (see Section A.1.1 for a listing) have a value one less in Fortran than C since in C the length includes the null terminating character. Thus, these constants represent the amount of space which must be allocated to hold the largest possible such string, rather than the maximum number of printable characters the string could contain. ...

Examples for "unless specified otherwise" are MPI_SUBARRAYS_SUPPORTED and MPI_ASYNC_PROTECTS_NONBLOCKING together with a further requirement for Fortran handles: Chapter 19 Language Bindings 19.1 Support for Fortran 19.1.1 Overview says: ... These constants exist for each Fortran support method, but not in the C header file. The values may be different for each Fortran support method. All other constants and the integer values of handles must be the same for each Fortran support method. ...

And additionally for MPI_SUBARRAYS_SUPPORTED and MPI_ASYNC_PROTECTS_NONBLOCKING if the Fortran compiler supports TYPE(*), DIMENSION(..), and the ASYNCHRONOUS attribute for external libraries, i.e. TS 29113 or Fortran 2018, which all modern Fortran compiler now do:

19.1.3 Fortran Support Through the mpi_f08 Module ... Use the ASYNCHRONOUS attribute to protect the buffers of nonblocking operations, and set the LOGICAL compile-time constant MPI_ASYNC_PROTECTS_NONBLOCKING to .TRUE. if the underlying Fortran compiler supports the ASYNCHRONOUS attribute for MPI communication (as part of TS 29113). See Section 19.1.6 for older compiler versions.

My comment: This is correctly done by mpich and Intel-MPI for such compilers OpenMPI has a serious bug, because it still sets MPI_SUBARRAYS_SUPPORTED to .FALSE. with same compilers.

• Set the LOGICAL compile-time constant MPI_SUBARRAYS_SUPPORTED to .TRUE. and declare choice buffers using the Fortran 2008 TS 29113 features assumed-type and assumed-rank, i.e., TYPE(*), DIMENSION(..) in all nonblocking, split collective and persistent communication routines, if the underlying Fortran compiler supports it. With this, noncontiguous sub-arrays can be used as buffers in nonblocking routines. Rationale. In all blocking routines, i.e., if the choice-buffer is not declared as ASYNCHRONOUS, the TS 29113 feature is not needed for the support of noncontiguous buffers because the compiler can pass the buffer by in-and-out-copy through a contiguous scratch array. (End of rationale.)

My comment: This is correctly done by mpich and Intel-MPI for such compilers OpenMPI has a serious bug, because it still sets MPI_SUBARRAYS_SUPPORTED to .FALSE. with same compilers.

For the mpi module, it is a bit more complicated, but folowing strong requirement is there:

19.1.3 Fortran Support Through the mpi Module ... • Provide explicit interfaces according to the Fortran routine interface specifications. This module therefore guarantees compile-time argument checking and allows positional and keyword-based argument lists. If an implementation is paired with a compiler that either does not support TYPE(*), DIMENSION(..) from TS 29113, or is otherwise unable to ignore the types of choice buffers, then the implementation must provide explicit interfaces only for MPI routines with no choice buffer arguments. See Section 19.1.6 for more details.

My comment: This is correctly done by OpenMPI for such compilers. Intel-MPI and mpich have a serious bug, because they still not provide compile-time argument checking and keyword-based argument lists for many routines with same compilers.

Based on this, the mpi module can also provide MPI_SUBARRAYS_SUPPORTED=.TRUE. and MPI_ASYNC_PROTECTS_NONBLOCKING =.TRUE.

And for mpif.h, both constants should be .FALSE.

jeffhammond commented 1 year ago

@RolfRabenseifner Thanks! I missed the text from "19.3.9 Constants" that clearly answers this.

Open MPI has a serious bug, because it still sets MPI_SUBARRAYS_SUPPORTED to .FALSE. with same compilers.

Compiler support is ~necessary~ helpful but insufficient to support subarrays. The implementation has to parse CFI_cdesc_t (or some compiler-specific alternative). It seems that Open MPI doesn't do that.

Even MPICH supports only some of the use cases. See https://github.com/pmodels/mpich/blob/main/src/binding/fortran/use_mpi_f08/wrappers_c/cdesc.c lines 31 and 43 for details.

The MPI standard allows some absolutely absurd things when it comes to subarrays. I tried to implement them in VAPAA (https://github.com/jeffhammond/vapaa/blob/main/source/cfi_util.c) and it is clear that nobody thought about this when it was added to MPI. The composition of a Fortran subarray with an arbitrary noncontiguous MPI datatype is absurd and - not surprisingly - awful to implement.

We are going to write a paper about implementing MPI 3.0 Fortran subarray support, at which point the Forum might consider adding some constrains on the features, so that there is some hope of it being implemented.

RolfRabenseifner commented 1 year ago

I'm wondering what OpenMPI and mpich is doing.

For blocking calls, strided arrays were and are always allowed.

Source program for three files: test_f08.f90, test_mpi.f90, test_mpif_h.f90

program test

!  USE mpi_f08        ! used in test_f08.f90
   USE mpi            ! used in test_mpi.f90
   IMPLICIT NONE
!  INCLUDE 'mpif.h'   ! used in test_mpif_h.f90

  integer :: my_rank, ierror
  real :: x(0:9), y(0:3)
  call MPI_Comm_rank(MPI_COMM_WORLD, my_rank, ierror)
  x(0) =   1.0
  x(3) = 301.0
  x(6) = 601.0
  x(9) = 901.0
  call MPI_Sendrecv(x(0:9:3), 4, MPI_REAL, my_rank, 99, & 
   &                          y, 4, MPI_REAL, my_rank, 99, &
   &                          MPI_COMM_WORLD, MPI_STATUS_IGNORE, ierror)
  print *, 'my_rank=', my_rank, ', snd_buf x(0:9:3)=', ', rcv_buf y(0:3)=', y
end test

I would expect that this small program compiled with each of the three Fortran MPI support methods and started with one MPI process will print the same, independent of the level of MPI support: MPI-1.1 (only mpif.h), MPI-2.0 - 2.2 (mpif.h and mpi module), or MPI-3.0 - 4.0 library (all three):

my_rank= 0 , snd_buf x(0:9:3)= 1.0 301.0 601.0 901.0 , rcv_buf y(0:3)= 1.0 301.0 601.0 901.0
jeffhammond commented 1 year ago

@RolfRabenseifner I closed this because the original question was answered. If you want to discuss MPI_SUBARRAY_SUPPORTED details, please create a new issue. I have a lot to say on this topic, having implemented it more completely than anyone else, as far as I know, but look at e.g. https://github.com/jeffhammond/vapaa/blob/main/tests/test_matrix_noncontig_2.F90 , because the simple use cases aren't the problem. That VAPAA test might pass because it's a single process test, but if you make it into a multi-process test and run it across a network rather than shared-memory, it may have problems.