[MPI3 Fortran] Deprecate mpif.h?
Bill Long
longb at cray.com
Sun Mar 7 12:46:02 CST 2010
N.M. Maclaren wrote:
> Perhaps I should spell out what is likely to become possible with
> Fortran 2008 and the TR for choice dummy arguments. Note I say "is
> likely to" - the TR is still being developed, and not everything I
> mention is in the current draft, though it has been agreed in principle.
>
> Bill: you might like to see if I have got anything wrong, omitted
> anything important or been misleading.
>
I'll give it a shot.
>
> Possibilities
> -------------
>
> They will be able to declare a choice dummy argument as assumed-type,
> which will eliminate the type checking. That's it. The actual type
> will still have to be passed separately, and heaven help the programmer
> if he gets it wrong. That will eliminate a breach of standard that
> currently causes trouble.
Removing the requirement that types of actual and dummy arguments match
is the sole purpose of type(*). I'm not sure what Nick means by 'the
actual type will still have to be passed'. There is no requirement or
intention that some extra information indicating the type of the actual
argument be passed to the subprogram. If an actual argument of type X
is passed to a subprogram that has an interface where the corresponding
dummy argument is specified type(*), and the subprogram is a function
written in C, then the interpretation of the argument in the function
should be as if it were declared type X.
Perhaps an aside (mainly for the C programmers) would be useful here.
There has been a lot of Fortran terminology used in this thread and I
suspect there are some more C-focused readers who are less familiar with
some of it. This is a brief conceptual description that I hope will help
clear the fog.
Fortran provides various argument passing semantics, which are most
often implemented in these three ways [noting that Fortran character
arguments are often an exception, and that none of these implementations
is specified in the standard]:
1) Call by value. The actual value of the argument is passed - a
concept very much like the same in C, and designed for interoperability
with C. The VALUE attribute has to be explicitly specified on the dummy
argument for this method to be used, and the interface for the callee
has to be visible in the caller.
2) Call by address. The address of the argument (or beginning of the
argument if is an array or structure) is passed. This is the most
common, and the only one that dates back to the pre-f90 era. This is
the equivalent to the common method of passing a pointer in C. The
categories of dummy arguments for which the corresponding actual gets
passed by address are ones that do not have the VALUE, ALLOCATABLE, or
POINTER attribute, are not assumed-rank. This leaves traditional
scalars, explicit-shape arrays, and assumed-size arrays, Also, this
method is used if there is no interface information for the callee
visible to the caller. (Hence the tie to pre-f90, which didn't have
explicit interfaces.)
3) Call by descriptor. The address of a descriptor of the argument is
passed. In addition to the address (as in (2) above), the descriptor
contains expanded information about the argument such as rank, type,
dimension information, etc. This method is used if the corresponding
dummy argument falls into a category where some of this extra
information is (or might be) needed by the subprogram. The categories of
dummy arguments for which the corresponding actual arguments get passed
by descriptor are: assumed-shape, allocatable, pointer, and
assumed-rank (new in TR). An interface for the callee has to be visible
in the caller for any of the situations where call by descriptor occurs.
[For a library like MPI, these interfaces would be provided in a module
such as MPI3 that is supplied by the library vendor.]
The primary focus of the TR is to provide a means for C to handle
arguments passed by descriptor (3).
With this vocabulary, a type(*) argument can be passed using either (2)
or (3) depending on other attributes of the dummy. Pass by value(1) is
explicitly prohibited.
Fortran's argument passing rules include the concept of an "element
sequence". An element sequence includes an array (in which case the
element sequence is the list of elements in array element order) or an
array element designator (in which case the element sequence starts with
that element and goes through the end of the array). If the dummy
argument is assumed-size or explicit shape (category 2 passing) then the
rank of the corresponding actual argument array does not have to match
the rank of the dummy. This permits a dummy declaration of
integer,dimension(*) :: buffer ! assumed-size dummy argument
which has traditionally been used for MPI-like buffer arguments. Actual
arrays of any rank can be associated with a dummy argument like this.
The assumed-type capability extends this to
type(*),dimension(*) :: buffer ! assumed-type and assumed-size
dummy argument
which will stop the compiler from complaining if there is a visible
interface and the actual is not type default INTEGER.
The major pothole in the element sequence road is that the actual
argument is assumed to have a memory layout that maps directly onto the
dummy argument, i.e. a contiguous block of memory in most
implementations. If the actual argument is not contiguous (possible for
one that is assumed-shape, assumed-rank, or has the POINTER attribute)
then for a call like this:
call sub (D)
the compiler will generate this sort of code in the caller:
create contiguous tmp of size of D
copy D to tmp ! copy-in operation
call sub(tmp)
copy tmp to D ! copy-out operation
deallocate tmp
This is the so-called "copy-in/copy-out" problem. The problem part
comes if sub is an asynchronous send or receive MPI routine because the
subroutine is working with the array tmp which is getting deleted on
return from sub, which is before the background thread is done with it.
[This problem is more general than MPI routines - any C routine that
saves a pointer to the argument and expects it to be valid for use after
the routine exits will lead to potential trouble. The fftw library fell
into this trap, for example.]
If the argument is passed by descriptor, then there is normally no
copy-in or copy-out since the dummy does not have to be contiguous.
This is the basis for most strategies for avoiding the copy-in /
copy-out problem.
Other schemes have been discussed, such as expanding the 'request'
argument to include information needed for the copy-out, and then teach
the compiler to defer the copy-out operation until the wait call with
that request argument. The extra information can also include whether
the copy is needed at all - no need to 'copy-out' if the MPI operation
was a send. As a practical hack, this would work well, but the "teach
the compiler" bit is tricky to word in the standard.
>
> [ TYPE(*) dummy arguments are syntactically and semantically almost
> identical to C or C++ void * function parameters. ]
>
> They will be be able to have the ASYNCHRONOUS attribute, which will be
> extended to support non-Fortran I/O (such as MPI non-blocking
> transfers).
Such an "extension" is not in any draft or accepted proposal, and
suffers from some technical issues. However, a program is permitted to
imply, via an interface, that an MPI routine is actually implemented
using asynchronous I/O, and the compiler will act accordingly, even if
no I/O of any kind is involved.
However, to remove the breach of standard and compiler
> problems, EVERY declaration for such an array in EVERY procedure that is
> 'active' between the MPI_Isend and MPI_Wait and declares that array must
> use the ASYNCHRONOUS attribute. If you work it through, this is
> essential, and not just Fortran being difficult. That will eliminate
> another breach of standard that currently causes trouble.
This is correct, and also why some users may find this approach to be
above the 'code-change-pain' threshold.
>
> They will be able to have the ALLOCATABLE dummy argument and the MPI
> interface will be able to allocate and deallocate the actual arguments
> appropriately. MPI will need to decide whether it uses this feature or
> not, and exactly how it will use it if it does, as it is an important
> part of the interface semantics.
>
> [ I don't see how MPI can use it without having a separate set of
> interfaces, as my reading of generic resolution doesn't allow for
> distinguishing on the ALLOCATABLE attribute (except against POINTER). ]
Specifying an allocatable dummy argument is only interesting if there is
some reason to allocate or deallocate memory for it. For the usual
send/receive routines this is not an issue. An actual argument with the
allocatable attribute can be associated with an assumed-size dummy (i.e.
what is currently done in f77-style interfaces).
>
> I don't think that POINTER dummy arguments are relevant to MPI for
> choice arguments, though they could well be for MPI_Buffer_attach and
> MPI_Buffer_detach. An implementation could use them for things like
> requests, but that's not a specification issue.
Specifying a dummy argument with the POINTER attribute is interesting if
there is a reason to change the target of the pointer. If not,
assumed-shape or assumed-rank are the preferred options - both allow for
non-contiguous actual arguments without copy-in/copy-out, as is the case
for POINTER.
>
> Now to the big one. They will continue to be able to use assumed-size
> or explicit-size dummy arguments, as in MPI 2.2, and that will continue to
> require a copy-in/copy-out for most implementations if passed an array
> section or assumed-shape array. MPI currently uses assumed-size dummy
> arguments. There's no change here.
>
> But they will also be able to use an assumed-rank dummy argument, which
> will take an actual argument of any rank (and even a scalar), and pass a
> descriptor that describes its shape. That will enable (but NOT require)
> all known implementations to avoid a copy-in/copy-out for array dummy
> arguments, but will NOT accept assumed-size actual arguments. That's a
> significant problem, and MPI will need to consider it.
>
The reason for rule against assumed-size actual arguments being
associated with dummies that fall into category (3) is that the
descriptor information includes the extents of each dimension and the
upper bound of the rightmost dimension of an assumed-size array is not
known. However, an assumed-size actual argument (which is necessarily a
dummy argument itself of the caller) is usually possible to avoid. The
issue is, again, the 'code-change-pain' threshold.
it is worth noting that none of the existing MPI routines is written to
accept a descriptor argument. If this were used as part of an interface
(assumed-rank dummy, for example), then someone would need to supply
either new routines or (most likely easier to maintain) a set of wrapper
routines. The wrappers would take part the descriptor and call the
corresponding old-style MPI routines - maybe many times, once for each
contiguous sub-piece of the ultimate argument. A main point of the TR
is to make it possible to write portable versions of these wrappers in C
while keeping the performance hit to a minimum. Writing them once will
be a chore. Doing it once for each implementation is probably too much
to expect.
Cheers,
Bill
--
Bill Long longb at cray.com
Fortran Technical Support & voice: 651-605-9024
Bioinformatics Software Development fax: 651-605-9142
Cray Inc./Cray Plaza, Suite 210/380 Jackson St./St. Paul, MN 55101
More information about the mpiwg-fortran
mailing list