Skip to content

Commit 1ae5439

Browse files
jtrongemphinney1100hppritcha
committed
Generate interfaces for C with bigcount
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 <mphinney@lanl.gov> Co-authored-by: Howard Pritchard <hppritcha@gmail.com> Signed-off-by: Jake Tronge <jtronge@lanl.gov>
1 parent c3bebd8 commit 1ae5439

File tree

859 files changed

+39430
-38549
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

859 files changed

+39430
-38549
lines changed

.gitignore

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,9 +534,10 @@ docs/_static
534534
docs/_static/css/custom.css
535535
docs/_templates
536536

537-
# Common Python virtual environment directory names
537+
# Common Python virtual environment and cache directory names
538538
venv
539539
py??
540+
__pycache__/
540541

541542
# Copies of PRRTE RST files (i.e., not source controlled in this tree)
542543
docs/prrte-rst-content
@@ -546,3 +547,11 @@ docs/schizo-ompi-rst-content
546547
# tarballs)
547548
docs/html
548549
docs/man
550+
551+
# Generated C Bindings
552+
ompi/mpi/c/generated_*.c
553+
554+
# Generated Fortran Bindings
555+
ompi/mpi/fortran/use-mpi-f08/*_generated.F90
556+
ompi/mpi/fortran/use-mpi-f08/base/*_generated.c
557+
ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces-generated.h

config/ompi_config_files.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ AC_DEFUN([OMPI_CONFIG_FILES],[
4040
ompi/mpi/fortran/use-mpi-ignore-tkr/mpi-ignore-tkr-file-interfaces.h
4141
ompi/mpi/fortran/use-mpi-ignore-tkr/mpi-ignore-tkr-removed-interfaces.h
4242
ompi/mpi/fortran/use-mpi-f08/Makefile
43-
ompi/mpi/fortran/use-mpi-f08/base/Makefile
4443
ompi/mpi/fortran/use-mpi-f08/profile/Makefile
44+
ompi/mpi/fortran/use-mpi-f08/base/Makefile
4545
ompi/mpi/fortran/use-mpi-f08/bindings/Makefile
4646
ompi/mpi/fortran/use-mpi-f08/mod/Makefile
4747
ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces.h

config/ompi_configure_options.m4

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,5 +253,26 @@ else
253253
fi
254254
AM_CONDITIONAL(OMPI_OMPIO_SUPPORT, test "$ompi_want_ompio" = "1")
255255

256+
AC_MSG_CHECKING([if want bigcount support])
257+
AC_ARG_ENABLE([bigcount],
258+
[AS_HELP_STRING([--enable-bigcount],
259+
[Enable the bigcount API])])
260+
if test "$enable_bigcount" = "yes" ; then
261+
AC_MSG_RESULT([yes])
262+
ompi_enable_bigcount=1
263+
else
264+
AC_MSG_RESULT([no])
265+
ompi_enable_bigcount=0
266+
fi
267+
AC_DEFINE_UNQUOTED([OMPI_BIGCOUNT],[$ompi_enable_bigcount],
268+
[Whether we want to compile bigcount API support])
269+
270+
# If the binding source files don't exist, then we need Python to generate them
271+
AM_PATH_PYTHON([3.6],,[:])
272+
binding_file="${srcdir}/ompi/mpi/c/ompi_send.c"
273+
AS_IF([! test -e "$binding_file" && test "$PYTHON" = ":"],
274+
[AC_MSG_ERROR([Open MPI requires Python >=3.6 for generating the bindings. Aborting])])
275+
AM_CONDITIONAL(OMPI_GENERATE_BINDINGS,[test "$PYTHON" != ":"])
276+
256277
])dnl
257278

config/ompi_fortran_check_ts.m4

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
dnl -*- shell-script -*-
2+
dnl
3+
dnl Copyright (c) 2019 Research Organization for Information Science
4+
dnl and Technology (RIST). All rights reserved.
5+
dnl $COPYRIGHT$
6+
dnl
7+
dnl Additional copyrights may follow
8+
dnl
9+
dnl $HEADER$
10+
dnl
11+
12+
# Check whether or not the C compiler supports ISO_Fortran_binding.h
13+
# Also check whether C and Fortran compiler interoperate.
14+
#
15+
# OMPI_FORTRAN_CHECK_TS([action if found], [action if not found])
16+
# ----------------------------------------------------
17+
AC_DEFUN([OMPI_FORTRAN_CHECK_TS],[
18+
AS_VAR_PUSHDEF([fortran_ts], [ompi_cv_fortran_have_ts])
19+
20+
AC_CHECK_HEADERS([ISO_Fortran_binding.h],
21+
[AC_CACHE_CHECK([if Fortran and C compilers support ISO_Fortran_binding.h], fortran_ts,
22+
[mkdir conftest.$$
23+
cd conftest.$$
24+
25+
# Try to compile the C bindings
26+
cat > conftest_c.c << EOF
27+
#include <ISO_Fortran_binding.h>
28+
29+
int is_contiguous_c(CFI_cdesc_t* x) {
30+
return CFI_is_contiguous(x);
31+
}
32+
EOF
33+
OPAL_LOG_COMMAND([$CC $CCFLAGS -c conftest_c.c],
34+
[cat > conftest.f90 << EOF
35+
module MOD_IS_CONTIGUOUS
36+
37+
interface
38+
39+
function is_contiguous(buf) BIND(C, name="is_contiguous_c")
40+
implicit none
41+
type(*), dimension(..) :: buf
42+
integer :: is_contiguous
43+
end function is_contiguous
44+
45+
end interface
46+
47+
end module
48+
49+
program test_is_contiguous
50+
use MOD_IS_CONTIGUOUS
51+
implicit none
52+
integer :: a0, a1(2), a2(2,2), a3(2,2,2)
53+
write (*,*) is_contiguous(a0)
54+
write (*,*) is_contiguous(a1)
55+
write (*,*) is_contiguous(a2)
56+
write (*,*) is_contiguous(a3)
57+
end program
58+
EOF
59+
OPAL_LOG_COMMAND([$FC $FCFLAGS $FCFLAGS_f90 -o conftest conftest.f90 conftest_c.o $LDFLAGS $LIBS],
60+
[AS_VAR_SET(fortran_ts, yes)],
61+
[AS_VAR_SET(fortran_ts, no)])],
62+
[AS_VAR_SET(fortran_ts, no)])
63+
cd ..
64+
rm -rf conftest.$$])],
65+
[AS_VAR_SET(fortran_ts, no)])
66+
67+
AS_VAR_IF(fortran_ts, [yes], [$1], [$2])
68+
AS_VAR_POPDEF([fortran_ts])dnl
69+
])

config/ompi_setup_mpi_fortran.m4

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -449,14 +449,27 @@ end program]])],
449449
# If we got all the stuff from above, then also look for the new
450450
# F08 syntax that we can use for the use_mpif08 module.
451451

452-
# We need to have ignore TKR functionality to build the mpi_f08
452+
OMPI_FORTRAN_HAVE_TS=0
453+
OMPI_MPI_SUBARRAYS_SUPPORTED=.false.
454+
OMPI_MPI_ASYNC_PROTECTS_NONBLOCKING=.false.
455+
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
456+
[OMPI_FORTRAN_CHECK_TS([OMPI_FORTRAN_HAVE_TS=1])])
457+
458+
# We need to have ignore TKR or the ISO Fortran bindings functionality to build the mpi_f08
453459
# module
454-
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS && \
455-
test $OMPI_FORTRAN_HAVE_IGNORE_TKR -eq 1],
456-
[OMPI_BUILD_FORTRAN_BINDINGS=$OMPI_FORTRAN_USEMPIF08_BINDINGS
457-
OMPI_FORTRAN_F08_PREDECL=$OMPI_FORTRAN_IGNORE_TKR_PREDECL
458-
OMPI_FORTRAN_F08_TYPE=$OMPI_FORTRAN_IGNORE_TKR_TYPE
459-
])
460+
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
461+
[AS_IF([test $OMPI_FORTRAN_HAVE_IGNORE_TKR -eq 1],
462+
[OMPI_BUILD_FORTRAN_BINDINGS=$OMPI_FORTRAN_USEMPIF08_BINDINGS
463+
OMPI_FORTRAN_F08_PREDECL=$OMPI_FORTRAN_IGNORE_TKR_PREDECL
464+
OMPI_FORTRAN_F08_TYPE=$OMPI_FORTRAN_IGNORE_TKR_TYPE
465+
])
466+
AS_IF([test $OMPI_FORTRAN_HAVE_TS -eq 1],
467+
[OMPI_BUILD_FORTRAN_BINDINGS=$OMPI_FORTRAN_USEMPIF08_BINDINGS
468+
OMPI_MPI_SUBARRAYS_SUPPORTED=.true.
469+
OMPI_MPI_ASYNC_PROTECTS_NONBLOCKING=.true.])])
470+
471+
AC_SUBST(OMPI_MPI_SUBARRAYS_SUPPORTED)
472+
AC_SUBST(OMPI_MPI_ASYNC_PROTECTS_NONBLOCKING)
460473

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

592605
OMPI_FORTRAN_NEED_WRAPPER_ROUTINES=1
593-
OMPI_FORTRAN_F08_PREDECL='!'
594-
OMPI_FORTRAN_F08_TYPE=real
595606
OMPI_FORTRAN_HAVE_F08_ASSUMED_RANK=0
596607
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS && \
597608
test $OMPI_BUILD_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
598609
[ # Look for Fortran 2008 assumed rank syntax
599610
OMPI_FORTRAN_CHECK_F08_ASSUMED_RANK(
600611
[ # If we have assumed rank, we can build the use
601612
# mpi_f08 module "better"
602-
OMPI_FORTRAN_F08_PREDECL='!'
603-
OMPI_FORTRAN_F08_TYPE='type(*), dimension(..)'
604613
OMPI_FORTRAN_HAVE_F08_ASSUMED_RANK=1])
605614

606615
# Which mpi_f08 implementation are we using?
@@ -630,6 +639,12 @@ end type test_mpi_handle],
630639
[OMPI_FORTRAN_ELEMENTAL_TYPE=])])
631640
AC_SUBST(OMPI_FORTRAN_ELEMENTAL_TYPE)
632641

642+
OMPI_FORTRAN_HAVE_C_ISO_FORTRAN=0
643+
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS && \
644+
test $OMPI_BUILD_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
645+
[OMPI_FORTRAN_CHECK_TS([OMPI_FORTRAN_HAVE_TS=1],
646+
[OMPI_FORTRAN_HAVE_TS=0])])
647+
633648
# Note: the current implementation *only* has wrappers;
634649
# there is no optimized implementation for a "good"
635650
# compiler. I'm leaving the above logic in place for
@@ -652,6 +667,8 @@ end type test_mpi_handle],
652667
AS_IF([test $OMPI_MIN_REQUIRED_FORTRAN_BINDINGS -gt $OMPI_BUILD_FORTRAN_BINDINGS],
653668
[AC_MSG_ERROR([Cannot build requested Fortran bindings, aborting])])
654669

670+
dnl AC_CONFIG_FILES([ompi/mpi/fortran/use-mpi-f08/bindings/mpi-f-interfaces-bind.h])
671+
655672
# -------------------
656673
# mpif.h final setup
657674
# -------------------
@@ -792,10 +809,9 @@ end type test_mpi_handle],
792809
# This goes into mpifort-wrapper-data.txt
793810
AC_SUBST(OMPI_FORTRAN_USEMPIF08_LIB)
794811

795-
# These go into interfaces/mpi-f08-interfaces-[no]bind.h (and
796-
# mpi-f*-interfaces*.h files)
797-
AC_SUBST(OMPI_FORTRAN_F08_PREDECL)
798-
AC_SUBST(OMPI_FORTRAN_F08_TYPE)
812+
# These go into mod/mpi-f08-interfaces.h
813+
AC_SUBST(OMPI_F08_IGNORE_TKR_PREDECL)
814+
AC_SUBST(OMPI_F08_IGNORE_TKR_TYPE)
799815

800816
AC_SUBST(OMPI_MPI_PREFIX)
801817
AC_SUBST(OMPI_MPI_BIND_PREFIX)
@@ -877,6 +893,25 @@ end type test_mpi_handle],
877893
# For configure-fortran-output.h
878894
AC_SUBST(OMPI_FORTRAN_HAVE_BIND_C)
879895

896+
AM_CONDITIONAL(OMPI_FORTRAN_HAVE_TS,
897+
[test $OMPI_FORTRAN_HAVE_TS -eq 1])
898+
AC_SUBST(OMPI_FORTRAN_HAVE_TS)
899+
AC_DEFINE_UNQUOTED([OMPI_FORTRAN_HAVE_TS],
900+
[$OMPI_FORTRAN_HAVE_TS],
901+
[For ompi/mpi/fortran/use-mpi-f08/base/ts.*: whether the compiler supports TS 29113 or not])
902+
903+
AS_IF([test $OMPI_FORTRAN_HAVE_TS -eq 1],
904+
[OMPI_F08_IGNORE_TKR_TYPE="type(*), dimension(..)"
905+
OMPI_F08_IGNORE_TKR_PREDECL="no attribute required for"
906+
OMPI_F08_BINDINGS_EXTENSION="ts"
907+
OMPI_F08_BINDINGS_TS_SUFFIX="ts"],
908+
[OMPI_F08_IGNORE_TKR_TYPE=$OMPI_FORTRAN_IGNORE_TKR_TYPE
909+
OMPI_F08_IGNORE_TKR_PREDECL=${OMPI_FORTRAN_IGNORE_TKR_PREDECL:1}
910+
OMPI_F08_BINDINGS_EXTENSION="f"
911+
OMPI_F08_BINDINGS_TS_SUFFIX=""])
912+
AC_SUBST(OMPI_F08_BINDINGS_EXTENSION)
913+
AC_SUBST(OMPI_F08_BINDINGS_TS_SUFFIX)
914+
880915
# Somewhat redundant because ompi/Makefile.am won't traverse into
881916
# ompi/mpi/fortran/use-mpi-f08 if it's not to be built, but we
882917
# might as well have ompi/mpi/fortran/use-mpi-f08/Makefile.am be

docs/developers/bindings.rst

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
C and Fortran Bindings
2+
======================
3+
4+
The C and Fortran (mpi_f08) bindings are generated from Python code in
5+
``ompi/mpi/bindings``. The C code is generated based on a template file for
6+
each function, with a header and a body containing error-checking and
7+
conversion code; the mpi_f08 Fortran bindings are generated from a single
8+
file ``ompi/mpi/fortran/use-mpi-f08/interface.in``.
9+
10+
The Python code depends on special prototype lines used with both the C and
11+
Fortran bindings. These "prototypes" are designed to be easy to parse and use
12+
specific type constants that can be mapped directly to the expanded
13+
language-specific code, error-handling, and conversion code.
14+
15+
C Bindings
16+
----------
17+
18+
This will walk through adding (or converting) a plain-C binding into a
19+
templated version controlled by the script.
20+
21+
As an example, for ``MPI_Send`` you might have a C file that looks something
22+
like this:
23+
24+
.. code-block:: c
25+
26+
#include "ompi_config.h"
27+
...other includes...
28+
29+
int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest,
30+
int tag, MPI_Comm comm)
31+
{
32+
...internal checks...
33+
return internal_mpi_send(buf, count, datatype, dest, tag, comm);
34+
}
35+
36+
To convert this to a template, you will have to first ensure that only a single
37+
function is defined in the file, removing or abstracting out static functions,
38+
and separating multiple definitions, such as ``MPI_Send`` and ``MPI_Isend``,
39+
into different files. The template should also not include any macro-processing
40+
that attempts to change the name of the function or parameter types; this code
41+
should be generated by the script, or abstracted into header files that can
42+
work easily with multiple functions.
43+
44+
At this point, the template should look like the example above, with a "header"
45+
section, with simple includes or macros, maybe a static global, and the
46+
function defintion and nothing else.
47+
48+
The next step is to convert the signature line into the prototype format that
49+
the script expects. For ``MPI_Send``, this should look something like this:
50+
51+
.. code-block:: c
52+
53+
PROTOTYPE ERROR_CLASS send(BUFFER buf, COUNT count, DATATYPE type, RANK dest,
54+
TAG tag, COMM comm)
55+
56+
Notice how the function name is changed, the ``MPI_`` prefix removed and the
57+
rest converted to lowercase, and also how each parameter is simplified into a
58+
``TYPE name`` format, where the ``TYPE`` conforms to an allowed list in
59+
``ompi/mpi/bindings/ompi_bindings/c_type.py``. For newer functions and types,
60+
you may have to extend the ``c_type.py`` file with a new class showing how to
61+
handle the type.
62+
63+
The final step is to update ``Makefile.am``, adding the template name, in this
64+
case ``send.c.in``, to the ``prototype_sources`` variable, and the generated
65+
file name, ``generated_send.c``, to ``interface_profile_sources``. The
66+
generated file name must be of the form ``generated_${basename}.c``, where
67+
``${basename}`` is the name of the template file stripped of all extensions.
68+
69+
Fortran Bindings
70+
----------------
71+
72+
To add a new Fortran binding, or update an existing one, one will need to
73+
modify the ``ompi/mpi/fortran/use-mpi-f08/interface.json`` file; this JSON file
74+
contains a list of prototype objects, including information about their name
75+
and each parameter passed. Below is an example for ``MPI_Waitall``:
76+
77+
.. code-block::
78+
79+
{
80+
"name": "waitall",
81+
"parameters": [
82+
{
83+
"type": "SHORTCUT_COUNT",
84+
"name": "count"
85+
},
86+
{
87+
"type": "REQUEST_ARRAY",
88+
"name": "array_of_requests",
89+
"dep_params": {
90+
"count": "count"
91+
}
92+
},
93+
{
94+
"type": "STATUS_ARRAY",
95+
"name": "array_of_statuses",
96+
"dep_params": {
97+
"count": "count"
98+
}
99+
}
100+
]
101+
}
102+
103+
This object includes two properties: the ``name`` property holding the
104+
subroutine name, converted to lowercase and the ``mpi_`` prefix removed; and
105+
the ``parameters`` property describing all parameters, their types and
106+
dependencies. Some parameters may depend on other types and this is listed in
107+
the ``dep_params`` field. An example of this can be seen with
108+
``array_of_requests`` above, in which ``dep_params`` holds a key-value pair
109+
``"count": "count"``, where the key ``count`` corresponds to a key required by
110+
the ``REQUEST_ARRAY`` type and the value ``count`` to the name of another
111+
parameter. These parameter dependencies are specific to the types used and are
112+
validated by the binding scripts.
113+
114+
The Fortran binding code not only generates Fortran, but also additional
115+
wrapping C code that calls into the C bindings, making conversions and checking
116+
for Fortran-specific error conditions as necessary. The following files will be
117+
generated by the script:
118+
119+
* ``ompi/mpi/fortran/use-mpi-f08/api_f08_generated.F90``
120+
* ``ompi/mpi/fortran/use-mpi-f08/base/api_f08_generated.c``
121+
* ``ompi/mpi/fortran/use-mpi-f08/base/api_f08_ts_generated.c``
122+
* ``ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces-generated.h``
123+
124+
The Fortran file ``api_f08_generated.F90`` contains all the internal subroutine
125+
definitions, each of which makes a call into corresponding C functions. Two
126+
different C files are generated: ``api_f08_ts_generated.c`` contains support
127+
for compilers with TS 29113 support, allowing the use of ``CFI_cdesc_t`` types
128+
(see `Fortran 2018`_ for more details); and ``api_f08_generated.c`` for
129+
compilers without TS 29113 support. The internal subroutine names are mapped to
130+
the external interface, including multiple interfaces for the bigcount version
131+
of functions, in ``mpi-f08-interfaces-generated.h``.
132+
133+
.. _Fortran 2018: https://fortranwiki.org/fortran/show/Fortran+2018
134+
135+
If a new type needs to be added, then one will need to extend
136+
``fortran_type.py`` in ``ompi/mpi/bindings/ompi_bindings`` with an additional
137+
type class specifying how to handle the type in the above generated files,
138+
including any required key-value attributes for more complicated types. New
139+
types use a ``Type`` base class with functions that can be implemented by
140+
derived classes, each returning expanded Fortran or C code.
141+
142+
Other Considerations
143+
--------------------
144+
145+
Keep in mind that the generated files will not be deleted with a ``make clean``
146+
or ``make distclean``; instead use ``make maintainer-clean`` to delete those.

docs/developers/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ probably don't need to read this section.
2222
gnu-autotools
2323
sphinx
2424
rst-for-markdown-expats.rst
25+
bindings

0 commit comments

Comments
 (0)