Skip to content

Commit 86be709

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. Note that there are additional changes needed to Open MPI for bigcount support. One is that the datatype system needs to be embiggened. This PR includes workarounds for this lack of support that will need to be changed once the datatype system is embiggened. These areas of code are marked with TODO:BIGCOUNT. Co-authored-by: mphinney1100 <[email protected]> Co-authored-by: Howard Pritchard <[email protected]> Signed-off-by: Jake Tronge <[email protected]>
1 parent 5ae1b96 commit 86be709

File tree

879 files changed

+40655
-39388
lines changed

Some content is hidden

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

879 files changed

+40655
-39388
lines changed

.gitignore

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,9 +516,10 @@ docs/_static
516516
docs/_static/css/custom.css
517517
docs/_templates
518518

519-
# Common Python virtual environment directory names
519+
# Common Python virtual environment and cache directory names
520520
venv
521521
py??
522+
__pycache__/
522523

523524
# Copies of PRRTE RST files (i.e., not source controlled in this tree)
524525
docs/prrte-rst-content
@@ -528,3 +529,11 @@ docs/schizo-ompi-rst-content
528529
# tarballs)
529530
docs/html
530531
docs/man
532+
533+
# Generated C Bindings
534+
ompi/mpi/c/*_generated*.c
535+
536+
# Generated Fortran Bindings
537+
ompi/mpi/fortran/use-mpi-f08/*_generated.F90
538+
ompi/mpi/fortran/use-mpi-f08/base/*_generated.c
539+
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
@@ -37,8 +37,8 @@ AC_DEFUN([OMPI_CONFIG_FILES],[
3737
ompi/mpi/fortran/use-mpi-ignore-tkr/mpi-ignore-tkr-file-interfaces.h
3838
ompi/mpi/fortran/use-mpi-ignore-tkr/mpi-ignore-tkr-removed-interfaces.h
3939
ompi/mpi/fortran/use-mpi-f08/Makefile
40-
ompi/mpi/fortran/use-mpi-f08/base/Makefile
4140
ompi/mpi/fortran/use-mpi-f08/profile/Makefile
41+
ompi/mpi/fortran/use-mpi-f08/base/Makefile
4242
ompi/mpi/fortran/use-mpi-f08/bindings/Makefile
4343
ompi/mpi/fortran/use-mpi-f08/mod/Makefile
4444
ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces.h

config/ompi_configure_options.m4

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

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

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
@@ -435,14 +435,27 @@ end program]])],
435435
# If we got all the stuff from above, then also look for the new
436436
# F08 syntax that we can use for the use_mpif08 module.
437437

438-
# We need to have ignore TKR functionality to build the mpi_f08
438+
OMPI_FORTRAN_HAVE_TS=0
439+
OMPI_MPI_SUBARRAYS_SUPPORTED=.false.
440+
OMPI_MPI_ASYNC_PROTECTS_NONBLOCKING=.false.
441+
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
442+
[OMPI_FORTRAN_CHECK_TS([OMPI_FORTRAN_HAVE_TS=1])])
443+
444+
# We need to have ignore TKR or the ISO Fortran bindings functionality to build the mpi_f08
439445
# module
440-
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS && \
441-
test $OMPI_FORTRAN_HAVE_IGNORE_TKR -eq 1],
442-
[OMPI_BUILD_FORTRAN_BINDINGS=$OMPI_FORTRAN_USEMPIF08_BINDINGS
443-
OMPI_FORTRAN_F08_PREDECL=$OMPI_FORTRAN_IGNORE_TKR_PREDECL
444-
OMPI_FORTRAN_F08_TYPE=$OMPI_FORTRAN_IGNORE_TKR_TYPE
445-
])
446+
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
447+
[AS_IF([test $OMPI_FORTRAN_HAVE_IGNORE_TKR -eq 1],
448+
[OMPI_BUILD_FORTRAN_BINDINGS=$OMPI_FORTRAN_USEMPIF08_BINDINGS
449+
OMPI_FORTRAN_F08_PREDECL=$OMPI_FORTRAN_IGNORE_TKR_PREDECL
450+
OMPI_FORTRAN_F08_TYPE=$OMPI_FORTRAN_IGNORE_TKR_TYPE
451+
])
452+
AS_IF([test $OMPI_FORTRAN_HAVE_TS -eq 1],
453+
[OMPI_BUILD_FORTRAN_BINDINGS=$OMPI_FORTRAN_USEMPIF08_BINDINGS
454+
OMPI_MPI_SUBARRAYS_SUPPORTED=.true.
455+
OMPI_MPI_ASYNC_PROTECTS_NONBLOCKING=.true.])])
456+
457+
AC_SUBST(OMPI_MPI_SUBARRAYS_SUPPORTED)
458+
AC_SUBST(OMPI_MPI_ASYNC_PROTECTS_NONBLOCKING)
446459

447460
# The overall "_BIND_C" variable will be set to 1 if we have all
448461
# the necessary forms of BIND(C)
@@ -576,17 +589,13 @@ end type test_mpi_handle],
576589
])
577590

578591
OMPI_FORTRAN_NEED_WRAPPER_ROUTINES=1
579-
OMPI_FORTRAN_F08_PREDECL='!'
580-
OMPI_FORTRAN_F08_TYPE=real
581592
OMPI_FORTRAN_HAVE_F08_ASSUMED_RANK=0
582593
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS && \
583594
test $OMPI_BUILD_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
584595
[ # Look for Fortran 2008 assumed rank syntax
585596
OMPI_FORTRAN_CHECK_F08_ASSUMED_RANK(
586597
[ # If we have assumed rank, we can build the use
587598
# mpi_f08 module "better"
588-
OMPI_FORTRAN_F08_PREDECL='!'
589-
OMPI_FORTRAN_F08_TYPE='type(*), dimension(..)'
590599
OMPI_FORTRAN_HAVE_F08_ASSUMED_RANK=1])
591600

592601
# Which mpi_f08 implementation are we using?
@@ -616,6 +625,12 @@ end type test_mpi_handle],
616625
[OMPI_FORTRAN_ELEMENTAL_TYPE=])])
617626
AC_SUBST(OMPI_FORTRAN_ELEMENTAL_TYPE)
618627

628+
OMPI_FORTRAN_HAVE_C_ISO_FORTRAN=0
629+
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS && \
630+
test $OMPI_BUILD_FORTRAN_BINDINGS -ge $OMPI_FORTRAN_USEMPIF08_BINDINGS],
631+
[OMPI_FORTRAN_CHECK_TS([OMPI_FORTRAN_HAVE_TS=1],
632+
[OMPI_FORTRAN_HAVE_TS=0])])
633+
619634
# Note: the current implementation *only* has wrappers;
620635
# there is no optimized implementation for a "good"
621636
# compiler. I'm leaving the above logic in place for
@@ -638,6 +653,8 @@ end type test_mpi_handle],
638653
AS_IF([test $OMPI_MIN_REQUIRED_FORTRAN_BINDINGS -gt $OMPI_BUILD_FORTRAN_BINDINGS],
639654
[AC_MSG_ERROR([Cannot build requested Fortran bindings, aborting])])
640655

656+
dnl AC_CONFIG_FILES([ompi/mpi/fortran/use-mpi-f08/bindings/mpi-f-interfaces-bind.h])
657+
641658
# -------------------
642659
# mpif.h final setup
643660
# -------------------
@@ -778,10 +795,9 @@ end type test_mpi_handle],
778795
# This goes into mpifort-wrapper-data.txt
779796
AC_SUBST(OMPI_FORTRAN_USEMPIF08_LIB)
780797

781-
# These go into interfaces/mpi-f08-interfaces-[no]bind.h (and
782-
# mpi-f*-interfaces*.h files)
783-
AC_SUBST(OMPI_FORTRAN_F08_PREDECL)
784-
AC_SUBST(OMPI_FORTRAN_F08_TYPE)
798+
# These go into mod/mpi-f08-interfaces.h
799+
AC_SUBST(OMPI_F08_IGNORE_TKR_PREDECL)
800+
AC_SUBST(OMPI_F08_IGNORE_TKR_TYPE)
785801

786802
AC_SUBST(OMPI_MPI_PREFIX)
787803
AC_SUBST(OMPI_MPI_BIND_PREFIX)
@@ -863,6 +879,25 @@ end type test_mpi_handle],
863879
# For configure-fortran-output.h
864880
AC_SUBST(OMPI_FORTRAN_HAVE_BIND_C)
865881

882+
AM_CONDITIONAL(OMPI_FORTRAN_HAVE_TS,
883+
[test $OMPI_FORTRAN_HAVE_TS -eq 1])
884+
AC_SUBST(OMPI_FORTRAN_HAVE_TS)
885+
AC_DEFINE_UNQUOTED([OMPI_FORTRAN_HAVE_TS],
886+
[$OMPI_FORTRAN_HAVE_TS],
887+
[For ompi/mpi/fortran/use-mpi-f08/base/ts.*: whether the compiler supports TS 29113 or not])
888+
889+
AS_IF([test $OMPI_FORTRAN_HAVE_TS -eq 1],
890+
[OMPI_F08_IGNORE_TKR_TYPE="type(*), dimension(..)"
891+
OMPI_F08_IGNORE_TKR_PREDECL="no attribute required for"
892+
OMPI_F08_BINDINGS_EXTENSION="ts"
893+
OMPI_F08_BINDINGS_TS_SUFFIX="ts"],
894+
[OMPI_F08_IGNORE_TKR_TYPE=$OMPI_FORTRAN_IGNORE_TKR_TYPE
895+
OMPI_F08_IGNORE_TKR_PREDECL=${OMPI_FORTRAN_IGNORE_TKR_PREDECL:1}
896+
OMPI_F08_BINDINGS_EXTENSION="f"
897+
OMPI_F08_BINDINGS_TS_SUFFIX=""])
898+
AC_SUBST(OMPI_F08_BINDINGS_EXTENSION)
899+
AC_SUBST(OMPI_F08_BINDINGS_TS_SUFFIX)
900+
866901
# Somewhat redundant because ompi/Makefile.am won't traverse into
867902
# ompi/mpi/fortran/use-mpi-f08 if it's not to be built, but we
868903
# 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)