Skip to content

Commit

Permalink
Generate interfaces for C with bigcount
Browse files Browse the repository at this point in the history
This adds scripts for generating the C API bindings from template files,
while also generating bigcount interfaces for those that require them.
The binding script also include initial support for the mpi_f08 Fortran
bindings, but doesn't yet make any changes to fortran/use-mpi-f08

Python >=3.6 is required for running these scripts, which is only
necessary when the binding files have not already been generated.
Users of the distribution tarball should not need to generate these
files and thus should not require Python.

Co-authored-by: mphinney1100 <[email protected]>
Co-authored-by: Howard Pritchard <[email protected]>
Signed-off-by: Jake Tronge <[email protected]>
  • Loading branch information
3 people committed Aug 12, 2024
1 parent c3bebd8 commit 1ae5439
Show file tree
Hide file tree
Showing 859 changed files with 39,430 additions and 38,549 deletions.
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -534,9 +534,10 @@ docs/_static
docs/_static/css/custom.css
docs/_templates

# Common Python virtual environment directory names
# Common Python virtual environment and cache directory names
venv
py??
__pycache__/

# Copies of PRRTE RST files (i.e., not source controlled in this tree)
docs/prrte-rst-content
Expand All @@ -546,3 +547,11 @@ docs/schizo-ompi-rst-content
# tarballs)
docs/html
docs/man

# Generated C Bindings
ompi/mpi/c/generated_*.c

# Generated Fortran Bindings
ompi/mpi/fortran/use-mpi-f08/*_generated.F90
ompi/mpi/fortran/use-mpi-f08/base/*_generated.c
ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces-generated.h
2 changes: 1 addition & 1 deletion config/ompi_config_files.m4
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ AC_DEFUN([OMPI_CONFIG_FILES],[
ompi/mpi/fortran/use-mpi-ignore-tkr/mpi-ignore-tkr-file-interfaces.h
ompi/mpi/fortran/use-mpi-ignore-tkr/mpi-ignore-tkr-removed-interfaces.h
ompi/mpi/fortran/use-mpi-f08/Makefile
ompi/mpi/fortran/use-mpi-f08/base/Makefile
ompi/mpi/fortran/use-mpi-f08/profile/Makefile
ompi/mpi/fortran/use-mpi-f08/base/Makefile
ompi/mpi/fortran/use-mpi-f08/bindings/Makefile
ompi/mpi/fortran/use-mpi-f08/mod/Makefile
ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces.h
Expand Down
21 changes: 21 additions & 0 deletions config/ompi_configure_options.m4
Original file line number Diff line number Diff line change
Expand Up @@ -253,5 +253,26 @@ else
fi
AM_CONDITIONAL(OMPI_OMPIO_SUPPORT, test "$ompi_want_ompio" = "1")

AC_MSG_CHECKING([if want bigcount support])
AC_ARG_ENABLE([bigcount],
[AS_HELP_STRING([--enable-bigcount],
[Enable the bigcount API])])
if test "$enable_bigcount" = "yes" ; then
AC_MSG_RESULT([yes])
ompi_enable_bigcount=1
else
AC_MSG_RESULT([no])
ompi_enable_bigcount=0
fi
AC_DEFINE_UNQUOTED([OMPI_BIGCOUNT],[$ompi_enable_bigcount],
[Whether we want to compile bigcount API support])

# If the binding source files don't exist, then we need Python to generate them
AM_PATH_PYTHON([3.6],,[:])
binding_file="${srcdir}/ompi/mpi/c/ompi_send.c"
AS_IF([! test -e "$binding_file" && test "$PYTHON" = ":"],
[AC_MSG_ERROR([Open MPI requires Python >=3.6 for generating the bindings. Aborting])])
AM_CONDITIONAL(OMPI_GENERATE_BINDINGS,[test "$PYTHON" != ":"])

])dnl

69 changes: 69 additions & 0 deletions config/ompi_fortran_check_ts.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
dnl -*- shell-script -*-
dnl
dnl Copyright (c) 2019 Research Organization for Information Science
dnl and Technology (RIST). All rights reserved.
dnl $COPYRIGHT$
dnl
dnl Additional copyrights may follow
dnl
dnl $HEADER$
dnl

# Check whether or not the C compiler supports ISO_Fortran_binding.h
# Also check whether C and Fortran compiler interoperate.
#
# OMPI_FORTRAN_CHECK_TS([action if found], [action if not found])
# ----------------------------------------------------
AC_DEFUN([OMPI_FORTRAN_CHECK_TS],[
AS_VAR_PUSHDEF([fortran_ts], [ompi_cv_fortran_have_ts])

AC_CHECK_HEADERS([ISO_Fortran_binding.h],
[AC_CACHE_CHECK([if Fortran and C compilers support ISO_Fortran_binding.h], fortran_ts,
[mkdir conftest.$$
cd conftest.$$

# Try to compile the C bindings
cat > conftest_c.c << EOF
#include <ISO_Fortran_binding.h>

int is_contiguous_c(CFI_cdesc_t* x) {
return CFI_is_contiguous(x);
}
EOF
OPAL_LOG_COMMAND([$CC $CCFLAGS -c conftest_c.c],
[cat > conftest.f90 << EOF
module MOD_IS_CONTIGUOUS

interface

function is_contiguous(buf) BIND(C, name="is_contiguous_c")
implicit none
type(*), dimension(..) :: buf
integer :: is_contiguous
end function is_contiguous

end interface

end module

program test_is_contiguous
use MOD_IS_CONTIGUOUS
implicit none
integer :: a0, a1(2), a2(2,2), a3(2,2,2)
write (*,*) is_contiguous(a0)
write (*,*) is_contiguous(a1)
write (*,*) is_contiguous(a2)
write (*,*) is_contiguous(a3)
end program
EOF
OPAL_LOG_COMMAND([$FC $FCFLAGS $FCFLAGS_f90 -o conftest conftest.f90 conftest_c.o $LDFLAGS $LIBS],
[AS_VAR_SET(fortran_ts, yes)],
[AS_VAR_SET(fortran_ts, no)])],
[AS_VAR_SET(fortran_ts, no)])
cd ..
rm -rf conftest.$$])],
[AS_VAR_SET(fortran_ts, no)])

AS_VAR_IF(fortran_ts, [yes], [$1], [$2])
AS_VAR_POPDEF([fortran_ts])dnl
])
65 changes: 50 additions & 15 deletions config/ompi_setup_mpi_fortran.m4
Original file line number Diff line number Diff line change
Expand Up @@ -449,14 +449,27 @@ end program]])],
# If we got all the stuff from above, then also look for the new
# F08 syntax that we can use for the use_mpif08 module.

# We need to have ignore TKR functionality to build the mpi_f08
OMPI_FORTRAN_HAVE_TS=0
OMPI_MPI_SUBARRAYS_SUPPORTED=.false.
OMPI_MPI_ASYNC_PROTECTS_NONBLOCKING=.false.
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
[OMPI_FORTRAN_CHECK_TS([OMPI_FORTRAN_HAVE_TS=1])])

# We need to have ignore TKR or the ISO Fortran bindings functionality to build the mpi_f08
# module
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS && \
test $OMPI_FORTRAN_HAVE_IGNORE_TKR -eq 1],
[OMPI_BUILD_FORTRAN_BINDINGS=$OMPI_FORTRAN_USEMPIF08_BINDINGS
OMPI_FORTRAN_F08_PREDECL=$OMPI_FORTRAN_IGNORE_TKR_PREDECL
OMPI_FORTRAN_F08_TYPE=$OMPI_FORTRAN_IGNORE_TKR_TYPE
])
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
[AS_IF([test $OMPI_FORTRAN_HAVE_IGNORE_TKR -eq 1],
[OMPI_BUILD_FORTRAN_BINDINGS=$OMPI_FORTRAN_USEMPIF08_BINDINGS
OMPI_FORTRAN_F08_PREDECL=$OMPI_FORTRAN_IGNORE_TKR_PREDECL
OMPI_FORTRAN_F08_TYPE=$OMPI_FORTRAN_IGNORE_TKR_TYPE
])
AS_IF([test $OMPI_FORTRAN_HAVE_TS -eq 1],
[OMPI_BUILD_FORTRAN_BINDINGS=$OMPI_FORTRAN_USEMPIF08_BINDINGS
OMPI_MPI_SUBARRAYS_SUPPORTED=.true.
OMPI_MPI_ASYNC_PROTECTS_NONBLOCKING=.true.])])

AC_SUBST(OMPI_MPI_SUBARRAYS_SUPPORTED)
AC_SUBST(OMPI_MPI_ASYNC_PROTECTS_NONBLOCKING)

# The overall "_BIND_C" variable will be set to 1 if we have all
# the necessary forms of BIND(C)
Expand Down Expand Up @@ -590,17 +603,13 @@ end type test_mpi_handle],
])

OMPI_FORTRAN_NEED_WRAPPER_ROUTINES=1
OMPI_FORTRAN_F08_PREDECL='!'
OMPI_FORTRAN_F08_TYPE=real
OMPI_FORTRAN_HAVE_F08_ASSUMED_RANK=0
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS && \
test $OMPI_BUILD_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
[ # Look for Fortran 2008 assumed rank syntax
OMPI_FORTRAN_CHECK_F08_ASSUMED_RANK(
[ # If we have assumed rank, we can build the use
# mpi_f08 module "better"
OMPI_FORTRAN_F08_PREDECL='!'
OMPI_FORTRAN_F08_TYPE='type(*), dimension(..)'
OMPI_FORTRAN_HAVE_F08_ASSUMED_RANK=1])

# Which mpi_f08 implementation are we using?
Expand Down Expand Up @@ -630,6 +639,12 @@ end type test_mpi_handle],
[OMPI_FORTRAN_ELEMENTAL_TYPE=])])
AC_SUBST(OMPI_FORTRAN_ELEMENTAL_TYPE)

OMPI_FORTRAN_HAVE_C_ISO_FORTRAN=0
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS && \
test $OMPI_BUILD_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
[OMPI_FORTRAN_CHECK_TS([OMPI_FORTRAN_HAVE_TS=1],
[OMPI_FORTRAN_HAVE_TS=0])])

# Note: the current implementation *only* has wrappers;
# there is no optimized implementation for a "good"
# compiler. I'm leaving the above logic in place for
Expand All @@ -652,6 +667,8 @@ end type test_mpi_handle],
AS_IF([test $OMPI_MIN_REQUIRED_FORTRAN_BINDINGS -gt $OMPI_BUILD_FORTRAN_BINDINGS],
[AC_MSG_ERROR([Cannot build requested Fortran bindings, aborting])])

dnl AC_CONFIG_FILES([ompi/mpi/fortran/use-mpi-f08/bindings/mpi-f-interfaces-bind.h])

# -------------------
# mpif.h final setup
# -------------------
Expand Down Expand Up @@ -792,10 +809,9 @@ end type test_mpi_handle],
# This goes into mpifort-wrapper-data.txt
AC_SUBST(OMPI_FORTRAN_USEMPIF08_LIB)

# These go into interfaces/mpi-f08-interfaces-[no]bind.h (and
# mpi-f*-interfaces*.h files)
AC_SUBST(OMPI_FORTRAN_F08_PREDECL)
AC_SUBST(OMPI_FORTRAN_F08_TYPE)
# These go into mod/mpi-f08-interfaces.h
AC_SUBST(OMPI_F08_IGNORE_TKR_PREDECL)
AC_SUBST(OMPI_F08_IGNORE_TKR_TYPE)

AC_SUBST(OMPI_MPI_PREFIX)
AC_SUBST(OMPI_MPI_BIND_PREFIX)
Expand Down Expand Up @@ -877,6 +893,25 @@ end type test_mpi_handle],
# For configure-fortran-output.h
AC_SUBST(OMPI_FORTRAN_HAVE_BIND_C)

AM_CONDITIONAL(OMPI_FORTRAN_HAVE_TS,
[test $OMPI_FORTRAN_HAVE_TS -eq 1])
AC_SUBST(OMPI_FORTRAN_HAVE_TS)
AC_DEFINE_UNQUOTED([OMPI_FORTRAN_HAVE_TS],
[$OMPI_FORTRAN_HAVE_TS],
[For ompi/mpi/fortran/use-mpi-f08/base/ts.*: whether the compiler supports TS 29113 or not])

AS_IF([test $OMPI_FORTRAN_HAVE_TS -eq 1],
[OMPI_F08_IGNORE_TKR_TYPE="type(*), dimension(..)"
OMPI_F08_IGNORE_TKR_PREDECL="no attribute required for"
OMPI_F08_BINDINGS_EXTENSION="ts"
OMPI_F08_BINDINGS_TS_SUFFIX="ts"],
[OMPI_F08_IGNORE_TKR_TYPE=$OMPI_FORTRAN_IGNORE_TKR_TYPE
OMPI_F08_IGNORE_TKR_PREDECL=${OMPI_FORTRAN_IGNORE_TKR_PREDECL:1}
OMPI_F08_BINDINGS_EXTENSION="f"
OMPI_F08_BINDINGS_TS_SUFFIX=""])
AC_SUBST(OMPI_F08_BINDINGS_EXTENSION)
AC_SUBST(OMPI_F08_BINDINGS_TS_SUFFIX)

# Somewhat redundant because ompi/Makefile.am won't traverse into
# ompi/mpi/fortran/use-mpi-f08 if it's not to be built, but we
# might as well have ompi/mpi/fortran/use-mpi-f08/Makefile.am be
Expand Down
146 changes: 146 additions & 0 deletions docs/developers/bindings.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
C and Fortran Bindings
======================

The C and Fortran (mpi_f08) bindings are generated from Python code in
``ompi/mpi/bindings``. The C code is generated based on a template file for
each function, with a header and a body containing error-checking and
conversion code; the mpi_f08 Fortran bindings are generated from a single
file ``ompi/mpi/fortran/use-mpi-f08/interface.in``.

The Python code depends on special prototype lines used with both the C and
Fortran bindings. These "prototypes" are designed to be easy to parse and use
specific type constants that can be mapped directly to the expanded
language-specific code, error-handling, and conversion code.

C Bindings
----------

This will walk through adding (or converting) a plain-C binding into a
templated version controlled by the script.

As an example, for ``MPI_Send`` you might have a C file that looks something
like this:

.. code-block:: c
#include "ompi_config.h"
...other includes...
int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest,
int tag, MPI_Comm comm)
{
...internal checks...
return internal_mpi_send(buf, count, datatype, dest, tag, comm);
}
To convert this to a template, you will have to first ensure that only a single
function is defined in the file, removing or abstracting out static functions,
and separating multiple definitions, such as ``MPI_Send`` and ``MPI_Isend``,
into different files. The template should also not include any macro-processing
that attempts to change the name of the function or parameter types; this code
should be generated by the script, or abstracted into header files that can
work easily with multiple functions.

At this point, the template should look like the example above, with a "header"
section, with simple includes or macros, maybe a static global, and the
function defintion and nothing else.

The next step is to convert the signature line into the prototype format that
the script expects. For ``MPI_Send``, this should look something like this:

.. code-block:: c
PROTOTYPE ERROR_CLASS send(BUFFER buf, COUNT count, DATATYPE type, RANK dest,
TAG tag, COMM comm)
Notice how the function name is changed, the ``MPI_`` prefix removed and the
rest converted to lowercase, and also how each parameter is simplified into a
``TYPE name`` format, where the ``TYPE`` conforms to an allowed list in
``ompi/mpi/bindings/ompi_bindings/c_type.py``. For newer functions and types,
you may have to extend the ``c_type.py`` file with a new class showing how to
handle the type.

The final step is to update ``Makefile.am``, adding the template name, in this
case ``send.c.in``, to the ``prototype_sources`` variable, and the generated
file name, ``generated_send.c``, to ``interface_profile_sources``. The
generated file name must be of the form ``generated_${basename}.c``, where
``${basename}`` is the name of the template file stripped of all extensions.

Fortran Bindings
----------------

To add a new Fortran binding, or update an existing one, one will need to
modify the ``ompi/mpi/fortran/use-mpi-f08/interface.json`` file; this JSON file
contains a list of prototype objects, including information about their name
and each parameter passed. Below is an example for ``MPI_Waitall``:

.. code-block::
{
"name": "waitall",
"parameters": [
{
"type": "SHORTCUT_COUNT",
"name": "count"
},
{
"type": "REQUEST_ARRAY",
"name": "array_of_requests",
"dep_params": {
"count": "count"
}
},
{
"type": "STATUS_ARRAY",
"name": "array_of_statuses",
"dep_params": {
"count": "count"
}
}
]
}
This object includes two properties: the ``name`` property holding the
subroutine name, converted to lowercase and the ``mpi_`` prefix removed; and
the ``parameters`` property describing all parameters, their types and
dependencies. Some parameters may depend on other types and this is listed in
the ``dep_params`` field. An example of this can be seen with
``array_of_requests`` above, in which ``dep_params`` holds a key-value pair
``"count": "count"``, where the key ``count`` corresponds to a key required by
the ``REQUEST_ARRAY`` type and the value ``count`` to the name of another
parameter. These parameter dependencies are specific to the types used and are
validated by the binding scripts.

The Fortran binding code not only generates Fortran, but also additional
wrapping C code that calls into the C bindings, making conversions and checking
for Fortran-specific error conditions as necessary. The following files will be
generated by the script:

* ``ompi/mpi/fortran/use-mpi-f08/api_f08_generated.F90``
* ``ompi/mpi/fortran/use-mpi-f08/base/api_f08_generated.c``
* ``ompi/mpi/fortran/use-mpi-f08/base/api_f08_ts_generated.c``
* ``ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces-generated.h``

The Fortran file ``api_f08_generated.F90`` contains all the internal subroutine
definitions, each of which makes a call into corresponding C functions. Two
different C files are generated: ``api_f08_ts_generated.c`` contains support
for compilers with TS 29113 support, allowing the use of ``CFI_cdesc_t`` types
(see `Fortran 2018`_ for more details); and ``api_f08_generated.c`` for
compilers without TS 29113 support. The internal subroutine names are mapped to
the external interface, including multiple interfaces for the bigcount version
of functions, in ``mpi-f08-interfaces-generated.h``.

.. _Fortran 2018: https://fortranwiki.org/fortran/show/Fortran+2018

If a new type needs to be added, then one will need to extend
``fortran_type.py`` in ``ompi/mpi/bindings/ompi_bindings`` with an additional
type class specifying how to handle the type in the above generated files,
including any required key-value attributes for more complicated types. New
types use a ``Type`` base class with functions that can be implemented by
derived classes, each returning expanded Fortran or C code.

Other Considerations
--------------------

Keep in mind that the generated files will not be deleted with a ``make clean``
or ``make distclean``; instead use ``make maintainer-clean`` to delete those.
1 change: 1 addition & 0 deletions docs/developers/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ probably don't need to read this section.
gnu-autotools
sphinx
rst-for-markdown-expats.rst
bindings
Loading

0 comments on commit 1ae5439

Please sign in to comment.