From 45db4288040499e023b57c867f765b39c192cc9b Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Fri, 6 Dec 2024 16:16:23 -0600 Subject: [PATCH 01/13] romio: fix a potential warning Need double cast to suppress warnings when converting between pointers and integers. Also remove an unused macro, HAVE_INT_LT_POINTER. --- src/mpi/romio/configure.ac | 4 +--- src/mpi/romio/mpi-io/glue/mpich/mpio_file.c | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/mpi/romio/configure.ac b/src/mpi/romio/configure.ac index da28bbd5761..0e05b4b6dea 100644 --- a/src/mpi/romio/configure.ac +++ b/src/mpi/romio/configure.ac @@ -21,7 +21,7 @@ dnl AC_CONFIG_AUX_DIR(../../../confdb) dnl Set the directory that contains the required install-sh, config.sub, dnl and config.guess . Make sure that these are updated (in MPICH, use dnl the top-level confdb files). This separate directory is used for -dnl the moment to allow ROMIO to be separatedly distributed. +dnl the moment to allow ROMIO to be separately distributed. dnl scripts. AC_CONFIG_AUX_DIR([confdb]) AC_CONFIG_MACRO_DIR([confdb]) @@ -516,8 +516,6 @@ fi ]) if test "$pac_cv_int_hold_pointer" != yes ; then AC_DEFINE(INT_LT_POINTER,1,[Define if int smaller than pointer]) - dnl Switch to a conforming name (start with HAVE or USE) - AC_DEFINE(HAVE_INT_LT_POINTER,1,[Define if int smaller than pointer]) fi # LL is the printf-style format name for output of a MPI_Offset. diff --git a/src/mpi/romio/mpi-io/glue/mpich/mpio_file.c b/src/mpi/romio/mpi-io/glue/mpich/mpio_file.c index 0ffb5efcf1d..54906393b8a 100644 --- a/src/mpi/romio/mpi-io/glue/mpich/mpio_file.c +++ b/src/mpi/romio/mpi-io/glue/mpich/mpio_file.c @@ -39,7 +39,7 @@ void MPIO_File_free(MPI_File * mpi_fh) MPI_File MPIO_File_f2c(MPI_Fint fh) { #ifndef INT_LT_POINTER - return (MPI_File) ((void *) fh); + return (MPI_File) ((void *) (intptr_t) fh); /* the extra cast is to get rid of a compiler warning on Exemplar. * The warning is because MPI_File points to a structure containing * longlongs, which may be 8-byte aligned. But MPI_Fint itself @@ -58,7 +58,7 @@ MPI_File MPIO_File_f2c(MPI_Fint fh) MPI_Fint MPIO_File_c2f(MPI_File fh) { #ifndef INT_LT_POINTER - return (MPI_Fint) fh; + return (MPI_Fint) (intptr_t) fh; #else int i; From 37f91642d0c97f7efa01ebf710934540d9311afd Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Tue, 5 Sep 2023 18:18:24 -0500 Subject: [PATCH 02/13] mpi.h: define MPI-IO constants in mpi.h Define the complete MPI-IO interface in mpi.h. In all_romio_symbols.c, we can use MPI_Request instead of MPIO_Reuqest since MPIO_Request is not longer defined in mpi.h (since it no longer includes mpio.h). --- src/binding/cxx/buildiface | 9 +-------- src/glue/romio/all_romio_symbols | 4 +++- src/include/mpi.h.in | 20 ++++++++++++++++++-- src/mpi/romio/include/mpio.h.in | 24 ++++++++++++++---------- 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/binding/cxx/buildiface b/src/binding/cxx/buildiface index 1c6ae9e4784..83f4106235c 100755 --- a/src/binding/cxx/buildiface +++ b/src/binding/cxx/buildiface @@ -1736,14 +1736,7 @@ sub print_call_args { if (defined($mytopclass{$lctype})) { $lctype = $mytopclass{$lctype}; } - # Handle the MPIO_Request problem (temp until ROMIO uses - # MPI_Requests) - $cast = ""; - if ($parm =~ /MPI_Request/ && - $class eq "file") { - $cast = "(MPIO_Request *)"; - } - print $OUTFD "$cast&(v$count.the_real_$lctype)"; + print $OUTFD "&(v$count.the_real_$lctype)"; } else { print $OUTFD "&v$count"; diff --git a/src/glue/romio/all_romio_symbols b/src/glue/romio/all_romio_symbols index 84ee707b680..fc6696376fb 100755 --- a/src/glue/romio/all_romio_symbols +++ b/src/glue/romio/all_romio_symbols @@ -138,7 +138,9 @@ while () { print OUTFD "${tab}{\n"; for ($x = 0; $x <= $#arglist; $x++) { - print OUTFD "${tab}${tab}$arglist[$x]"; + my $a = $arglist[$x]; + $a =~ s/MPIO_Request/MPI_Request/; + print OUTFD "${tab}${tab}$a"; if ($arglist[$x] =~ /\*/) { print OUTFD " = NULL;\n"; } diff --git a/src/include/mpi.h.in b/src/include/mpi.h.in index 3e28e5307db..80b71af2ff2 100644 --- a/src/include/mpi.h.in +++ b/src/include/mpi.h.in @@ -504,6 +504,9 @@ static const MPI_Datatype mpich_mpi_offset MPICH_ATTR_TYPE_TAG(MPI_Offset) = MPI #define MPI_MAX_PSET_NAME_LEN 256 #define MPI_MAX_INFO_KEY 255 #define MPI_MAX_INFO_VAL 1024 +#define MPI_MAX_DATAREP_STRING 128 + +#define MPI_DISPLACEMENT_CURRENT ((MPI_Offset) -54278278) /* MPI-3 window flavors */ typedef enum MPIR_Win_flavor { @@ -622,6 +625,21 @@ enum MPIR_Combiner_enum { #define MPI_THREAD_SERIALIZED 2 #define MPI_THREAD_MULTIPLE 3 +/* MPI-IO constants */ +#define MPI_MODE_RDONLY 2 /* ADIO_RDONLY */ +#define MPI_MODE_RDWR 8 /* ADIO_RDWR */ +#define MPI_MODE_WRONLY 4 /* ADIO_WRONLY */ +#define MPI_MODE_CREATE 1 /* ADIO_CREATE */ +#define MPI_MODE_EXCL 64 /* ADIO_EXCL */ +#define MPI_MODE_DELETE_ON_CLOSE 16 /* ADIO_DELETE_ON_CLOSE */ +#define MPI_MODE_UNIQUE_OPEN 32 /* ADIO_UNIQUE_OPEN */ +#define MPI_MODE_APPEND 128 /* ADIO_APPEND */ +#define MPI_MODE_SEQUENTIAL 256 /* ADIO_SEQUENTIAL */ + +#define MPI_SEEK_SET 600 +#define MPI_SEEK_CUR 602 +#define MPI_SEEK_END 604 + /* MPI's error classes */ #define MPI_SUCCESS 0 /* Successful return code */ /* Communication argument parameters */ @@ -1027,8 +1045,6 @@ typedef struct MPIX_Iov { /* We require that the C compiler support prototypes */ #include -@HAVE_ROMIO@ - /* The f2c and c2f APIs exist as real functions, but these macros allows * for backward MPICH ABI compatibility. */ diff --git a/src/mpi/romio/include/mpio.h.in b/src/mpi/romio/include/mpio.h.in index c0322fdb1ad..6aa84e38b6e 100644 --- a/src/mpi/romio/include/mpio.h.in +++ b/src/mpi/romio/include/mpio.h.in @@ -82,6 +82,8 @@ typedef int MPI_Fint; # define MPI_MAX_INFO_VAL 1024 #endif +#ifndef MPI_MODE_RDONLY +/* only define these if they are not defined in mpi.h */ #define MPI_MODE_RDONLY 2 /* ADIO_RDONLY */ #define MPI_MODE_RDWR 8 /* ADIO_RDWR */ #define MPI_MODE_WRONLY 4 /* ADIO_WRONLY */ @@ -92,26 +94,28 @@ typedef int MPI_Fint; #define MPI_MODE_APPEND 128 /* ADIO_APPEND */ #define MPI_MODE_SEQUENTIAL 256 /* ADIO_SEQUENTIAL */ -#define MPI_DISPLACEMENT_CURRENT -54278278 - -#ifndef MPICH -/* FIXME: Make sure that we get a consistent definition of MPI_FILE_NULL - in MPICH */ -/* MPICH defines null object handles differently */ -#define MPI_FILE_NULL ((MPI_File) 0) -#endif -#define MPIO_REQUEST_NULL ((MPIO_Request) 0) - #define MPI_SEEK_SET 600 #define MPI_SEEK_CUR 602 #define MPI_SEEK_END 604 +#define MPI_DISPLACEMENT_CURRENT -54278278 + /* Open MPI: don't define MPI_MAX_DATAREP_STRING here; it's defined in OMPI's mpi.h. */ #ifndef OPEN_MPI #define MPI_MAX_DATAREP_STRING 128 #endif +#endif + +#ifndef MPICH +/* FIXME: Make sure that we get a consistent definition of MPI_FILE_NULL + in MPICH */ +/* MPICH defines null object handles differently */ +#define MPI_FILE_NULL ((MPI_File) 0) +#endif +#define MPIO_REQUEST_NULL ((MPIO_Request) 0) + #ifndef HAVE_MPI_DARRAY_SUBARRAY /* *INDENT-OFF* */ @HAVE_MPI_DARRAY_SUBARRAY@ From 8fefc5109b4de79a34ccc24ca108a762099de12f Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Thu, 31 Aug 2023 11:45:14 -0500 Subject: [PATCH 03/13] binding/c: add io_api.txt Add io_api.txt and generate io bindings --- maint/gen_binding_c.py | 3 + src/binding/c/io_api.txt | 205 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 src/binding/c/io_api.txt diff --git a/maint/gen_binding_c.py b/maint/gen_binding_c.py index d2f50ef74b8..345fcf57130 100644 --- a/maint/gen_binding_c.py +++ b/maint/gen_binding_c.py @@ -19,6 +19,9 @@ def main(): abi_dir = "src/binding/abi" func_list = load_C_func_list(binding_dir) + io_func_list = [f for f in func_list if f['dir'] == 'io'] + func_list = [f for f in func_list if f['dir'] != 'io'] + # -- Loading extra api prototypes (needed until other `buildiface` scripts are updated) G.mpi_declares = [] diff --git a/src/binding/c/io_api.txt b/src/binding/c/io_api.txt new file mode 100644 index 00000000000..90f6261c08d --- /dev/null +++ b/src/binding/c/io_api.txt @@ -0,0 +1,205 @@ +# vim: set ft=c: + +MPI_File_open: + .desc: Opens a file + +MPI_File_close: + .desc: Closes a file + +MPI_File_delete: + .desc: Deletes a file + +MPI_File_c2f: + .desc: Translates a C file handle to a Fortran file handle + .impl: direct +{ +#ifndef HAVE_ROMIO + return 0; +#else + return MPIR_File_c2f_impl(file); +#endif +} + +MPI_File_f2c: + .desc: Translates a Fortran file handle to a C file handle + .impl: direct +{ +#ifndef HAVE_ROMIO + return 0; +#else + return MPIR_File_f2c_impl(file); +#endif +} + +MPI_File_sync: + .desc: Causes all previous writes to be transferred + +MPI_File_get_amode: + .desc: Returns the file access mode + .skip: global_cs + +MPI_File_get_atomicity: + .desc: Returns the atomicity mode + .skip: global_cs + +MPI_File_get_byte_offset: + .desc: Returns the absolute byte position in + .skip: global_cs + +MPI_File_get_type_extent: + .desc: Returns the extent of datatype in the file + .poly_impl: use_aint + +MPI_File_get_group: + .desc: Returns the group of processes that + +MPI_File_get_info: + .desc: Returns the hints for a file that are actually being used by MPI + +MPI_File_get_position: + .desc: Returns the current position of the + +MPI_File_get_position_shared: + .desc: Returns the current position of the + +MPI_File_get_size: + .desc: Returns the file size + .skip: global_cs + +MPI_File_get_view: + .desc: Returns the file view + +MPI_File_iread_all: + .desc: Nonblocking collective read using individual file pointer + +MPI_File_iread_at_all: + .desc: Nonblocking collective read using explicit offset + +MPI_File_iread_at: + .desc: Nonblocking read using explicit offset + +MPI_File_iread: + .desc: Nonblocking read using individual file pointer + +MPI_File_iread_shared: + .desc: Nonblocking read using shared file pointer + +MPI_File_iwrite_all: + .desc: Nonblocking collective write using individual file pointer + +MPI_File_iwrite_at_all: + .desc: Nonblocking collective write using explicit offset + +MPI_File_iwrite_at: + .desc: Nonblocking write using explicit offset + +MPI_File_iwrite: + .desc: Nonblocking write using individual file pointer + +MPI_File_iwrite_shared: + .desc: Nonblocking write using shared file pointer + +MPI_File_open: + .desc: Opens a file + +MPI_File_preallocate: + .desc: Preallocates storage space for a file + +MPI_File_read_at_all_begin: + .desc: Begin a split collective read using explicit offset + +MPI_File_read_at_all_end: + .desc: Complete a split collective read using + +MPI_File_read_all_begin: + .desc: Begin a split collective read using individual file pointer + +MPI_File_read_all: + .desc: Collective read using individual file pointer + +MPI_File_read_all_end: + .desc: Complete a split collective read using + +MPI_File_read_at_all: + .desc: Collective read using explicit offset + +MPI_File_read_at: + .desc: Read using explicit offset + +MPI_File_read: + .desc: Read using individual file pointer + +MPI_File_read_ordered_begin: + .desc: Begin a split collective read using shared file pointer + +MPI_File_read_ordered: + .desc: Collective read using shared file pointer + +MPI_File_read_ordered_end: + .desc: Complete a split collective read using shared file pointer + +MPI_File_read_shared: + .desc: Read using shared file pointer + +MPI_File_seek: + .desc: Updates the individual file pointer + +MPI_File_seek_shared: + .desc: Updates the shared file pointer + +MPI_File_set_atomicity: + .desc: Sets the atomicity mode + +MPI_File_set_info: + .desc: Sets new values for the hints associated with a file + +MPI_File_set_size: + .desc: Sets the file size + +MPI_File_set_view: + .desc: Sets the file view +{ -- error_check -- disp + if (disp != MPI_DISPLACEMENT_CURRENT) { + MPIR_ERRTEST_ARGNEG(disp, "disp", mpi_errno); + } +} + +MPI_File_write_at_all_begin: + .desc: Begin a split collective write using + +MPI_File_write_at_all_end: + .desc: Complete a split collective write using explicit offset + +MPI_File_write_all_begin: + .desc: Begin a split collective write using + +MPI_File_write_all: + .desc: Collective write using individual file pointer + +MPI_File_write_all_end: + .desc: Complete a split collective write using individual file pointer + +MPI_File_write_at_all: + .desc: Collective write using explicit offset + +MPI_File_write_at: + .desc: Write using explicit offset + +MPI_File_write: + .desc: Write using individual file pointer + +MPI_File_write_ordered_begin: + .desc: Begin a split collective write using shared file pointer + +MPI_File_write_ordered: + .desc: Collective write using shared file pointer + +MPI_File_write_ordered_end: + .desc: Complete a split collective write using shared file pointer + +MPI_File_write_shared: + .desc: Write using shared file pointer + +MPI_Register_datarep: + .desc: Register a set of user-provided data conversion + .poly_impl: separate From 927d7fbca8a33f6d326f7e1248c47f136c14ca11 Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Sun, 1 Dec 2024 11:31:18 -0600 Subject: [PATCH 04/13] binding/c: fixup for MPI_Register_datarep This function is now defined in src/binding/c/io_api.txt. --- maint/local_python/binding_common.py | 4 +++- src/binding/c/datatype_api.txt | 9 --------- src/mpi/errhan/errnames.txt | 2 -- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/maint/local_python/binding_common.py b/maint/local_python/binding_common.py index f53603e5c05..edaff6ca917 100644 --- a/maint/local_python/binding_common.py +++ b/maint/local_python/binding_common.py @@ -119,7 +119,9 @@ def get_C_param(param, func, mapping): if param['func_type']: param_type = param['func_type'] if mapping['_name'].startswith("BIG_"): - param_type += "_c" + # hard list the limited number of large count function types + if re.match(r'MPI_User_function|MPI_Datarep_conversion_function', param_type): + param_type += "_c" if param_type in G.mpix_symbols: param_type = re.sub(r'MPI_', 'MPIX_', param_type) diff --git a/src/binding/c/datatype_api.txt b/src/binding/c/datatype_api.txt index 63234904e81..495023c5dbb 100644 --- a/src/binding/c/datatype_api.txt +++ b/src/binding/c/datatype_api.txt @@ -201,15 +201,6 @@ MPI_Unpack_external: } } -MPI_Register_datarep: not_implemented - .desc: Register a set of user-provided data conversion -{ - /* FIXME UNIMPLEMENTED */ - mpi_errno = - MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__, MPI_ERR_OTHER, - "**notimpl", 0); -} - MPI_Status_set_elements: .desc: Set the number of elements in a status { diff --git a/src/mpi/errhan/errnames.txt b/src/mpi/errhan/errnames.txt index 9198104035d..35c8c01fac6 100644 --- a/src/mpi/errhan/errnames.txt +++ b/src/mpi/errhan/errnames.txt @@ -923,8 +923,6 @@ is too big (> MPIU_SHMW_GHND_SZ) **mpi_attr_get %C %d %p %p:MPI_Attr_get(%C, keyval=%d, attr_value=%p, flag=%p) failed **mpi_attr_delete:MPI_Attr_delete failed **mpi_attr_delete %C %d:MPI_Attr_delete(%C, keyval=%d) failed -**mpi_register_datarep:MPI_Register_datarep failed -**mpi_register_datarep %s %p %p %p %p:MPI_Register_datarep(datarep=%s, read_conversion_fn=%p, write_conversion_fn=%p, dtype_file_extent_fn=%p, extra_state=%p) failed # MPIR functions From 7f4a857258b8cbaf8d9df77e2978561a0f0c5638 Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Fri, 6 Dec 2024 15:14:35 -0600 Subject: [PATCH 05/13] binding/c: suppress warnings on missing validations We don't have error checking for async_thing, amode, whence. --- src/binding/c/async_api.txt | 2 ++ src/binding/c/io_api.txt | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/binding/c/async_api.txt b/src/binding/c/async_api.txt index b3d0e0f9d01..9a948c2faef 100644 --- a/src/binding/c/async_api.txt +++ b/src/binding/c/async_api.txt @@ -13,6 +13,7 @@ MPIX_Async_get_state: .return: EXTRA_STATE async_thing: ASYNC_THING, [opaque pointer for async thing] .impl: direct + .skip: validate-ASYNC_THING { return MPIR_Async_thing_get_state(async_thing); } @@ -22,6 +23,7 @@ MPIX_Async_spawn: poll_fn: FUNCTION, func_type=MPIX_Async_poll_function, [user defined poll function for progressing async things] extra_state: EXTRA_STATE, [extra state for callback function] stream: STREAM, [stream object] + .skip: validate-ASYNC_THING { mpi_errno = MPIR_Async_thing_spawn(async_thing, poll_fn, extra_state, stream_ptr); if (mpi_errno) goto fn_fail; diff --git a/src/binding/c/io_api.txt b/src/binding/c/io_api.txt index 90f6261c08d..02d3257b74f 100644 --- a/src/binding/c/io_api.txt +++ b/src/binding/c/io_api.txt @@ -2,6 +2,7 @@ MPI_File_open: .desc: Opens a file + .skip: validate-amode MPI_File_close: .desc: Closes a file @@ -143,9 +144,11 @@ MPI_File_read_shared: MPI_File_seek: .desc: Updates the individual file pointer + .skip: validate-whence MPI_File_seek_shared: .desc: Updates the shared file pointer + .skip: validate-whence MPI_File_set_atomicity: .desc: Sets the atomicity mode From 606ead8d7a566fd411c0a9c495a038cbec4dc61c Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Wed, 4 Dec 2024 21:17:14 -0600 Subject: [PATCH 06/13] binding/python: refactor gen_binding_c.py Wrap the code that generates c_bindings.c in a function. This prepares for later adding io binding generations. ROMIO bindings will be thinner than non-IO functions. So we will a separate function to generate IO bindings. --- maint/gen_binding_c.py | 93 ++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/maint/gen_binding_c.py b/maint/gen_binding_c.py index 345fcf57130..81977f846a0 100644 --- a/maint/gen_binding_c.py +++ b/maint/gen_binding_c.py @@ -54,9 +54,6 @@ def main(): # -- Generating code -- - G.out = [] - G.out.append("#include \"mpiimpl.h\"") - G.out.append("") G.doc3_src_txt = [] G.poly_aliases = [] # large-count mansrc aliases G.need_dump_romio_reference = True @@ -67,9 +64,6 @@ def dump_out(file_path): dump_c_file(file_path, G.out) # add to mpi_sources for dump_Makefile_mk() G.mpi_sources.append(file_path) - G.out = [] - G.out.append("#include \"mpiimpl.h\"") - G.out.append("") G.need_dump_romio_reference = True def dump_func(func, manpage_out): @@ -98,52 +92,61 @@ def dump_func_abi(func): dump_mpi_c(func, True) del func['_is_abi'] - # ---- - for func in func_list: - G.err_codes = {} - manpage_out = [] - - if 'replace' in func and 'body' not in func: - continue + def dump_c_binding(): + G.out = [] + G.out.append("#include \"mpiimpl.h\"") + G.out.append("") + for func in func_list: + G.err_codes = {} + manpage_out = [] - dump_func(func, manpage_out) - if '_replaces' in func: - for t_func in func['_replaces']: - dump_func(t_func, manpage_out) + if 'replace' in func and 'body' not in func: + continue - if 'single-source' not in G.opts: - # dump individual functions in separate source files - dump_out(get_func_file_path(func, c_dir)) + dump_func(func, manpage_out) + if '_replaces' in func: + for t_func in func['_replaces']: + dump_func(t_func, manpage_out) - if 'single-source' in G.opts: - # otherwise, dump all functions in binding.c - dump_out(c_dir + "/c_binding.c") + if 'single-source' not in G.opts: + # dump individual functions in separate source files + dump_out(get_func_file_path(func, c_dir)) + G.out = [] + G.out.append("#include \"mpiimpl.h\"") + G.out.append("") - # ---- dump c_binding_abi.c - G.out = [] - G.out.append("#include \"mpiimpl.h\"") - G.out.append("#include \"mpi_abi_util.h\"") - G.out.append("") + if 'single-source' in G.opts: + # otherwise, dump all functions in binding.c + dump_out(c_dir + "/c_binding.c") - for func in func_list: - if 'replace' in func and 'body' not in func: - continue + def dump_c_binding_abi(): + G.out = [] + G.out.append("#include \"mpiimpl.h\"") + G.out.append("#include \"mpi_abi_util.h\"") + G.out.append("") - if re.match(r'MPIX_', func['name']): - if re.match(r'MPIX_(Grequest_|Type_iov)', func['name']): - # needed by ROMIO - pass - else: + for func in func_list: + if 'replace' in func and 'body' not in func: continue - dump_func_abi(func) - if '_replaces' in func: - for t_func in func['_replaces']: - dump_func_abi(t_func) - - abi_file_path = abi_dir + "/c_binding_abi.c" - G.check_write_path(abi_file_path) - dump_c_file(abi_file_path, G.out) - G.out = [] + + if re.match(r'MPIX_', func['name']): + if re.match(r'MPIX_(Grequest_|Type_iov)', func['name']): + # needed by ROMIO + pass + else: + continue + dump_func_abi(func) + if '_replaces' in func: + for t_func in func['_replaces']: + dump_func_abi(t_func) + + abi_file_path = abi_dir + "/c_binding_abi.c" + G.check_write_path(abi_file_path) + dump_c_file(abi_file_path, G.out) + + # ---- + dump_c_binding() + dump_c_binding_abi() if 'output-mansrc' in G.opts: f = c_dir + '/mansrc/' + 'poly_aliases.lst' From 795cfd9c237fa62d47ad614906e871946685b21d Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Fri, 6 Dec 2024 10:51:28 -0600 Subject: [PATCH 07/13] binding/python: refactor binding_c.py Refactor code to function dump_body_of_routine. This is a preparation for generating io bindings. Since ROMIO is designed on top of the rest of MPI, we will handle differently for parameter filtering and error checking, but the part that handles large count and calling the internal impl functions can be shared. --- maint/local_python/binding_c.py | 133 +++++++++++++++++--------------- 1 file changed, 70 insertions(+), 63 deletions(-) diff --git a/maint/local_python/binding_c.py b/maint/local_python/binding_c.py index f219ee4e194..24120403c33 100644 --- a/maint/local_python/binding_c.py +++ b/maint/local_python/binding_c.py @@ -1466,41 +1466,6 @@ def dump_function_normal(func): check_early_returns(func) G.out.append("") - # ---- - def dump_body_of_routine(): - do_threadcomm = False - if RE.search(r'threadcomm', func['extra'], re.IGNORECASE): - do_threadcomm = True - G.out.append("#ifdef ENABLE_THREADCOMM") - dump_if_open("comm_ptr->threadcomm") - dump_body_threadcomm(func) - dump_else_open() - G.out.append("#endif") - dump_else_close() - - if 'body' in func: - if func['_is_large'] and func['_poly_impl'] == "separate": - if 'code-large_count' not in func: - raise Exception("%s missing large count code block." % func['name']) - for l in func['code-large_count']: - G.out.append(l) - else: - for l in func['body']: - G.out.append(l) - elif 'impl' in func: - if RE.match(r'mpid', func['impl'], re.IGNORECASE): - dump_body_impl(func, "mpid") - elif RE.match(r'topo_fns->(\w+)', func['impl'], re.IGNORECASE): - dump_body_topo_fns(func, RE.m.group(1)) - else: - print("Error: unhandled special impl: [%s]" % func['impl']) - elif func['dir'] == 'coll': - dump_body_coll(func) - else: - dump_body_impl(func, "mpir") - - if do_threadcomm: - dump_if_close() # ---- G.out.append("/* ... body of routine ... */") @@ -1511,34 +1476,7 @@ def dump_body_of_routine(): G.out.append("goto fn_exit;") dump_if_close() - if func['_is_large'] and 'code-large_count' not in func: - # BIG but internally is using MPI_Aint - impl_args_save = copy.copy(func['_impl_arg_list']) - - dump_if_open("sizeof(MPI_Count) == sizeof(MPI_Aint)") - # Same size, just casting the _impl_arg_list - add_poly_impl_cast(func) - dump_body_of_routine() - - dump_else() - # Need filter to check limits and potentially swap args - func['_impl_arg_list'] = copy.copy(impl_args_save) - G.out.append("/* MPI_Count is bigger than MPI_Aint */") - dump_poly_pre_filter(func) - dump_body_of_routine() - dump_poly_post_filter(func) - - dump_if_close() - - elif not func['_is_large'] and func['_has_poly'] and func['_poly_impl'] != "separate": - # SMALL but internally is using MPI_Aint - dump_poly_pre_filter(func) - dump_body_of_routine() - dump_poly_post_filter(func) - - else: - # normal - dump_body_of_routine() + dump_body_of_routine(func) G.out.append("/* ... end of body of routine ... */") @@ -1959,6 +1897,75 @@ def dump_body_reduce_equal(func): dump_line_with_break("mpi_errno = %s(%s);" % (impl, args)) dump_error_check("") +def dump_body_of_routine(func): + def dump_body_normal(): + if 'body' in func: + if func['_is_large'] and func['_poly_impl'] == "separate": + if 'code-large_count' not in func: + raise Exception("%s missing large count code block." % func['name']) + for l in func['code-large_count']: + G.out.append(l) + else: + for l in func['body']: + G.out.append(l) + elif 'impl' in func: + if RE.match(r'mpid', func['impl'], re.IGNORECASE): + dump_body_impl(func, "mpid") + elif RE.match(r'topo_fns->(\w+)', func['impl'], re.IGNORECASE): + dump_body_topo_fns(func, RE.m.group(1)) + else: + print("Error: unhandled special impl: [%s]" % func['impl']) + elif func['dir'] == 'coll': + dump_body_coll(func) + else: + dump_body_impl(func, "mpir") + + def dump_body_internal(): + do_threadcomm = False + if RE.search(r'threadcomm', func['extra'], re.IGNORECASE): + do_threadcomm = True + G.out.append("#ifdef ENABLE_THREADCOMM") + dump_if_open("comm_ptr->threadcomm") + dump_body_threadcomm(func) + dump_else_open() + G.out.append("#endif") + dump_else_close() + + dump_body_normal() + + if do_threadcomm: + dump_if_close() + + # ---- + if func['_is_large'] and 'code-large_count' not in func: + # BIG but internally is using MPI_Aint + impl_args_save = copy.copy(func['_impl_arg_list']) + + dump_if_open("sizeof(MPI_Count) == sizeof(MPI_Aint)") + # Same size, just casting the _impl_arg_list + add_poly_impl_cast(func) + dump_body_internal() + + dump_else() + # Need filter to check limits and potentially swap args + func['_impl_arg_list'] = copy.copy(impl_args_save) + G.out.append("/* MPI_Count is bigger than MPI_Aint */") + dump_poly_pre_filter(func) + dump_body_internal() + dump_poly_post_filter(func) + + dump_if_close() + + elif not func['_is_large'] and func['_has_poly'] and func['_poly_impl'] != "separate": + # SMALL but internally is using MPI_Aint + dump_poly_pre_filter(func) + dump_body_internal() + dump_poly_post_filter(func) + + else: + # normal + dump_body_internal() + def dump_function_replace(func, repl_call): G.out.append("int mpi_errno = MPI_SUCCESS;") From c420807bf345256eecfa72f35ac95af02880f897 Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Mon, 2 Dec 2024 14:23:01 -0600 Subject: [PATCH 08/13] binding/fortran: fixup double listing io functions --- maint/gen_binding_f08.py | 7 ------- maint/gen_binding_f77.py | 7 ------- maint/gen_binding_f90.py | 4 ---- 3 files changed, 18 deletions(-) diff --git a/maint/gen_binding_f08.py b/maint/gen_binding_f08.py index 77df0964c94..0af0904b764 100644 --- a/maint/gen_binding_f08.py +++ b/maint/gen_binding_f08.py @@ -19,13 +19,6 @@ def main(): G.check_write_path("%s/wrappers_f/" % f08_dir) G.check_write_path("%s/wrappers_c/" % f08_dir) func_list = load_C_func_list(binding_dir, True) # suppress noise - if "no-mpiio" in G.opts: - # a few MPI_File_xxx functions are already in (MPI_File_xxx_errhandler) - func_list = [f for f in func_list if not f['name'].startswith('MPI_File_')] - else: - # FIXME: until romio interface is generated - func_list.extend(get_mpiio_func_list()) - func_list.append(G.FUNCS['mpi_f_sync_reg']) # preprocess get_real_POLY_kinds() diff --git a/maint/gen_binding_f77.py b/maint/gen_binding_f77.py index c4bbd43c367..dc56f779c31 100644 --- a/maint/gen_binding_f77.py +++ b/maint/gen_binding_f77.py @@ -19,14 +19,7 @@ def main(): func_list = load_C_func_list(binding_dir, True) # suppress noise - if "no-mpiio" in G.opts: - # a few MPI_File_xxx functions are already in (MPI_File_xxx_errhandler) - func_list = [f for f in func_list if not f['name'].startswith('MPI_File_')] - else: - # FIXME: until romio interface is generated - func_list.extend(get_mpiio_func_list()) func_list.extend(get_f77_dummy_func_list()) - func_list.append(G.FUNCS['mpi_f_sync_reg']) # preprocess for func in func_list: diff --git a/maint/gen_binding_f90.py b/maint/gen_binding_f90.py index f71e6a1bdf4..2aa95c9defa 100644 --- a/maint/gen_binding_f90.py +++ b/maint/gen_binding_f90.py @@ -17,10 +17,6 @@ def main(): f90_dir = "src/binding/fortran/use_mpi" G.check_write_path("%s/" % f90_dir) func_list = load_C_func_list(binding_dir, True) # suppress noise - if "no-mpiio" in G.opts: - func_list = [f for f in func_list if not f['name'].startswith('MPI_File_')] - else: - func_list.extend(get_mpiio_func_list()) func_list.extend(get_f77_dummy_func_list()) def has_cptr(func): From 117a7e442240bd4894998b71f3d922e58261253f Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Tue, 3 Dec 2024 11:40:55 -0600 Subject: [PATCH 09/13] romio: skip binding sources if FROM_MPICH MPICH will generate the binding layer. Now that libromio just supply internal code, we no longer need worry about libromio vs libpromio. We don't separate man pages and include mpio.h in mpi.h either. --- Makefile.am | 21 +++++---------------- src/mpi/Makefile.mk | 25 ------------------------- src/mpi/romio/configure.ac | 6 +++++- src/mpi/romio/mpi-io/Makefile.mk | 2 ++ 4 files changed, 12 insertions(+), 42 deletions(-) diff --git a/Makefile.am b/Makefile.am index 1d4afd58ed4..d926a32c0f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,6 +54,11 @@ external_libs = @WRAPPER_LIBS@ mpi_convenience_libs = pmpi_convenience_libs = @mpllib@ @hwloclib@ @jsonlib@ @yaksalib@ @pmilib@ +if BUILD_ROMIO + external_subdirs += src/mpi/romio + pmpi_convenience_libs += src/mpi/romio/libromio.la +endif + # NOTE on our semi-unconventional usage of DIST_SUBDIRS: # The automake manual recommends thinking of DIST_SUBDIRS as the list of all # *configured* subdirectories. The normal autotools model involves @@ -136,12 +141,6 @@ lib_lib@MPILIBNAME@_la_LDFLAGS = $(ABIVERSIONFLAGS) lib_lib@MPILIBNAME@_la_CPPFLAGS = $(AM_CPPFLAGS) -DMPICH_MPI_FROM_PMPI lib_lib@MPILIBNAME@_la_LIBADD = lib/lib@PMPILIBNAME@.la $(mpi_convenience_libs) -if BUILD_ROMIO - # libpromio contains the PMPI symbols (unlike libpmpi, which contains MPI - # symbols) and should be added to libpmpi - lib_lib@PMPILIBNAME@_la_LIBADD += src/mpi/romio/libpromio.la - lib_lib@MPILIBNAME@_la_LIBADD += src/mpi/romio/libromio.la -endif else !BUILD_PROFILING_LIB lib_LTLIBRARIES += lib/lib@MPILIBNAME@.la @@ -151,9 +150,6 @@ lib_lib@MPILIBNAME@_la_CPPFLAGS = $(AM_CPPFLAGS) lib_lib@MPILIBNAME@_la_LIBADD = $(external_libs) $(pmpi_convenience_libs) $(mpi_convenience_libs) EXTRA_lib_lib@MPILIBNAME@_la_DEPENDENCIES = $(pmpi_convenience_libs) $(mpi_convenience_libs) -if BUILD_ROMIO - lib_lib@MPILIBNAME@_la_LIBADD += src/mpi/romio/libromio.la -endif endif !BUILD_PROFILING_LIB if BUILD_ABI_LIB @@ -177,10 +173,6 @@ lib_lib@MPIABILIBNAME@_la_LDFLAGS = $(ABIVERSIONFLAGS) lib_lib@MPIABILIBNAME@_la_CPPFLAGS = $(AM_CPPFLAGS) -DMPICH_MPI_FROM_PMPI $(abi_cppflags) lib_lib@MPIABILIBNAME@_la_LIBADD = lib/lib@PMPIABILIBNAME@.la $(mpi_convenience_libs) -if BUILD_ROMIO - lib_lib@PMPIABILIBNAME@_la_LIBADD += src/mpi/romio/libpromio_abi.la - lib_lib@MPIABILIBNAME@_la_LIBADD += src/mpi/romio/libromio_abi.la -endif else !BUILD_PROFILING_LIB lib_LTLIBRARIES += lib/lib@MPIABILIBNAME@.la @@ -190,9 +182,6 @@ lib_lib@MPIABILIBNAME@_la_CPPFLAGS = $(AM_CPPFLAGS) $(abi_cppflags) lib_lib@MPIABILIBNAME@_la_LIBADD = $(external_libs) $(pmpi_convenience_libs) $(mpi_convenience_libs) EXTRA_lib_lib@MPIABILIBNAME@_la_DEPENDENCIES = $(pmpi_convenience_libs) $(mpi_convenience_libs) -if BUILD_ROMIO - lib_lib@MPIABILIBNAME@_la_LIBADD += src/mpi/romio/libromio_abi.la -endif endif !BUILD_PROFILING_LIB endif BUILD_ABI_LIB diff --git a/src/mpi/Makefile.mk b/src/mpi/Makefile.mk index 8d7c4236ee6..b0fa296ff04 100644 --- a/src/mpi/Makefile.mk +++ b/src/mpi/Makefile.mk @@ -22,30 +22,5 @@ include $(top_srcdir)/src/mpi/topo/Makefile.mk include $(top_srcdir)/src/mpi/stream/Makefile.mk include $(top_srcdir)/src/mpi/threadcomm/Makefile.mk -if BUILD_ROMIO -SUBDIRS += src/mpi/romio -DIST_SUBDIRS += src/mpi/romio -MANDOC_SUBDIRS += src/mpi/romio -HTMLDOC_SUBDIRS += src/mpi/romio - -# This was previously a hard copy (not a symlink) performed by config.status -# (specified via AC_CONFIG_COMMANDS). Ideally we would eliminate this "copy" -# altogether and just set -Iromio_include_dir, but MPE2's build system uses -# $(top_builddir)/bin/mpicc that can't handle more than one include dir. -# -# Using a symlink allows us to avoid trying to capture the full dependency chain -# of MPICH/mpio.h --> ROMIO/mpio.h --> ROMIO/mpio.h.in --> ROMIO/config.status --> ...MORE_AUTOTOOLS... -BUILT_SOURCES += $(top_builddir)/src/include/mpio.h -$(top_builddir)/src/include/mpio.h: $(top_builddir)/src/mpi/romio/include/mpio.h - if test ! -h $(top_builddir)/src/include/mpio.h ; then \ - rm -f $(top_builddir)/src/include/mpio.h ; \ - ( cd $(top_builddir)/src/include && \ - $(LN_S) ../mpi/romio/include/mpio.h ) ; \ - fi - -DISTCLEANFILES += $(top_builddir)/src/include/mpio.h - -endif BUILD_ROMIO - # dir is present but currently intentionally unbuilt #include $(top_srcdir)/src/mpi/io/Makefile.mk diff --git a/src/mpi/romio/configure.ac b/src/mpi/romio/configure.ac index 0e05b4b6dea..6a42e3254d1 100644 --- a/src/mpi/romio/configure.ac +++ b/src/mpi/romio/configure.ac @@ -105,6 +105,8 @@ AC_ARG_VAR([FROM_OMPI],[set to "yes" if building ROMIO inside of Open MPI]) FROM_OMPI=${FROM_OMPI:-no} if test "$FROM_OMPI" = 1 ; then FROM_OMPI=yes ; fi +AM_CONDITIONAL([BUILD_BINDING], [test "$FROM_MPICH" != "yes"]) + # MPL AC_ARG_VAR([MPLLIBNAME],[can be used to override the name of the MPL library (default: "mpl")]) MPLLIBNAME=${MPLLIBNAME:-"mpl"} @@ -691,7 +693,9 @@ AM_CONDITIONAL([BUILD_MPIO_ERRHAN],[false]) # if we don't have weak symbol support, we must build a separate convenience # library in order to provide the "PMPI_" symbols -AM_CONDITIONAL([BUILD_PROFILING_LIB],[test "x$HAVE_WEAK_SYMBOLS" = "x0"]) +# MPICH will generate separate binding layer, thus we can skip PROFILING LIB +# if build inside MPICH +AM_CONDITIONAL([BUILD_PROFILING_LIB],[test "x$HAVE_WEAK_SYMBOLS" = "x0" -a "$FROM_MPICH" != "yes"]) # disable visibility if building profiling library if test "x$HAVE_WEAK_SYMBOLS" = "x0" ; then VISIBILITY_CFLAGS="" diff --git a/src/mpi/romio/mpi-io/Makefile.mk b/src/mpi/romio/mpi-io/Makefile.mk index 3bde1b94256..621fa85016f 100644 --- a/src/mpi/romio/mpi-io/Makefile.mk +++ b/src/mpi/romio/mpi-io/Makefile.mk @@ -9,6 +9,7 @@ include $(top_srcdir)/mpi-io/fortran/Makefile.mk AM_CPPFLAGS += -I$(top_builddir)/mpi-io -I$(top_srcdir)/mpi-io noinst_HEADERS += mpi-io/mpioimpl.h mpi-io/mpioprof.h +if BUILD_BINDING romio_mpi_sources += \ mpi-io/close.c \ mpi-io/delete.c \ @@ -68,6 +69,7 @@ romio_mpi_sources += \ mpi-io/write_ordb.c \ mpi-io/write_orde.c \ mpi-io/write_sh.c +endif BUILD_BINDING # non-MPI/PMPI sources that will be included in libromio From 9a10e4f024d6166c2cd4622c7cac87423cc58b3b Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Thu, 5 Dec 2024 12:08:06 -0600 Subject: [PATCH 10/13] Makefile: fix abi build using romio We no longer have any convenience libraries that need go into libmpi.so when libpmpi.so is also built. Thus, the legacy mpi_convenience_libs variable is no longer in use. However, we need differentiate libromio from the other convenience libraries for the ABI build. ROMIO depends on MPI, thus will need separate version for ABI and non-ABI build. Thus, we create two variables -- mpi_convenience_libs and abi_convenience_libs. Note: the former reuses the name but now with different meanings. --- Makefile.am | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Makefile.am b/Makefile.am index d926a32c0f3..ab103004b40 100644 --- a/Makefile.am +++ b/Makefile.am @@ -51,12 +51,20 @@ errnames_txt_files = external_subdirs = @mplsrcdir@ @hwlocsrcdir@ @jsonsrcdir@ @yaksasrcdir@ @pmisrcdir@ external_ldflags = @mpllibdir@ @yaksalibdir@ external_libs = @WRAPPER_LIBS@ -mpi_convenience_libs = + +# convenience libs that do not depend on MPI pmpi_convenience_libs = @mpllib@ @hwloclib@ @jsonlib@ @yaksalib@ @pmilib@ +# convenience libs that depend on MPI (either MPI functions or MPI constants) +mpi_convenience_libs = +abi_convenience_libs = + if BUILD_ROMIO external_subdirs += src/mpi/romio - pmpi_convenience_libs += src/mpi/romio/libromio.la + mpi_convenience_libs += src/mpi/romio/libromio.la +if BUILD_ABI_LIB + abi_convenience_libs += src/mpi/romio/libromio_abi.la +endif endif # NOTE on our semi-unconventional usage of DIST_SUBDIRS: @@ -129,8 +137,8 @@ if BUILD_PROFILING_LIB lib_LTLIBRARIES += lib/lib@PMPILIBNAME@.la lib_lib@PMPILIBNAME@_la_SOURCES = $(mpi_sources) $(mpi_core_sources) lib_lib@PMPILIBNAME@_la_LDFLAGS = $(external_ldflags) $(ABIVERSIONFLAGS) -lib_lib@PMPILIBNAME@_la_LIBADD = $(external_libs) $(pmpi_convenience_libs) -EXTRA_lib_lib@PMPILIBNAME@_la_DEPENDENCIES = $(pmpi_convenience_libs) +lib_lib@PMPILIBNAME@_la_LIBADD = $(external_libs) $(pmpi_convenience_libs) $(mpi_convenience_libs) +EXTRA_lib_lib@PMPILIBNAME@_la_DEPENDENCIES = $(pmpi_convenience_libs) $(mpi_convenience_libs) # lib@MPILIBNAME@.la might depend on lib@PMPILIBNAME@.la. We add them # in that order to lib_LTLIBRARIES so libtool doesn't get @@ -139,7 +147,7 @@ lib_LTLIBRARIES += lib/lib@MPILIBNAME@.la lib_lib@MPILIBNAME@_la_SOURCES = $(mpi_sources) lib_lib@MPILIBNAME@_la_LDFLAGS = $(ABIVERSIONFLAGS) lib_lib@MPILIBNAME@_la_CPPFLAGS = $(AM_CPPFLAGS) -DMPICH_MPI_FROM_PMPI -lib_lib@MPILIBNAME@_la_LIBADD = lib/lib@PMPILIBNAME@.la $(mpi_convenience_libs) +lib_lib@MPILIBNAME@_la_LIBADD = lib/lib@PMPILIBNAME@.la else !BUILD_PROFILING_LIB @@ -161,8 +169,8 @@ lib_LTLIBRARIES += lib/lib@PMPIABILIBNAME@.la lib_lib@PMPIABILIBNAME@_la_SOURCES = $(mpi_abi_sources) $(mpi_f77_sources) $(mpi_core_sources) lib_lib@PMPIABILIBNAME@_la_LDFLAGS = $(external_ldflags) $(ABIVERSIONFLAGS) lib_lib@PMPIABILIBNAME@_la_CPPFLAGS = $(AM_CPPFLAGS) -DF77_USE_PMPI $(abi_cppflags) -lib_lib@PMPIABILIBNAME@_la_LIBADD = $(external_libs) $(pmpi_convenience_libs) -EXTRA_lib_lib@PMPIABILIBNAME@_la_DEPENDENCIES = $(pmpi_convenience_libs) +lib_lib@PMPIABILIBNAME@_la_LIBADD = $(external_libs) $(pmpi_convenience_libs) $(abi_convenience_libs) +EXTRA_lib_lib@PMPIABILIBNAME@_la_DEPENDENCIES = $(pmpi_convenience_libs) $(abi_convenience_libs) # lib@MPIABILIBNAME@.la might depend on lib@PMPIABILIBNAME@.la. We add them # in that order to lib_LTLIBRARIES so libtool doesn't get @@ -171,7 +179,7 @@ lib_LTLIBRARIES += lib/lib@MPIABILIBNAME@.la lib_lib@MPIABILIBNAME@_la_SOURCES = $(mpi_abi_sources) lib_lib@MPIABILIBNAME@_la_LDFLAGS = $(ABIVERSIONFLAGS) lib_lib@MPIABILIBNAME@_la_CPPFLAGS = $(AM_CPPFLAGS) -DMPICH_MPI_FROM_PMPI $(abi_cppflags) -lib_lib@MPIABILIBNAME@_la_LIBADD = lib/lib@PMPIABILIBNAME@.la $(mpi_convenience_libs) +lib_lib@MPIABILIBNAME@_la_LIBADD = lib/lib@PMPIABILIBNAME@.la else !BUILD_PROFILING_LIB @@ -179,8 +187,8 @@ lib_LTLIBRARIES += lib/lib@MPIABILIBNAME@.la lib_lib@MPIABILIBNAME@_la_SOURCES = $(mpi_abi_sources) $(mpi_core_sources) lib_lib@MPIABILIBNAME@_la_LDFLAGS = $(external_ldflags) $(ABIVERSIONFLAGS) lib_lib@MPIABILIBNAME@_la_CPPFLAGS = $(AM_CPPFLAGS) $(abi_cppflags) -lib_lib@MPIABILIBNAME@_la_LIBADD = $(external_libs) $(pmpi_convenience_libs) $(mpi_convenience_libs) -EXTRA_lib_lib@MPIABILIBNAME@_la_DEPENDENCIES = $(pmpi_convenience_libs) $(mpi_convenience_libs) +lib_lib@MPIABILIBNAME@_la_LIBADD = $(external_libs) $(pmpi_convenience_libs) $(abi_convenience_libs) +EXTRA_lib_lib@MPIABILIBNAME@_la_DEPENDENCIES = $(pmpi_convenience_libs) $(abi_convenience_libs) endif !BUILD_PROFILING_LIB endif BUILD_ABI_LIB From 92c1a4beb8d42fb252e987dad77b26b07ed566c1 Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Fri, 1 Sep 2023 15:37:35 -0500 Subject: [PATCH 11/13] binding/python: generate io bindings Generate io bindings including prototypes in mpi_proto.h and mpir_impl.h. src/binding/c/io.c caintains all the IO binding functions that calls the corresponding _impl functions. But it is not included in the Makefile yet. Dump the prototypes for io impl functions separately to allow inserting necessary missing declarations such as MPIR_Ext_cs_enter/exit. IO functions need use MPIR_Ext_cs_enter/exit for global cs. Now it gets more complicated, refactor into dump_global_cs_enter/exit for better readability. --- .gitignore | 1 + maint/gen_binding_c.py | 22 +++++++- maint/local_python/__init__.py | 1 + maint/local_python/binding_c.py | 97 +++++++++++++++++++++++++++------ src/binding/abi/Makefile.mk | 3 +- 5 files changed, 103 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 07252f6710e..3424dffb881 100644 --- a/.gitignore +++ b/.gitignore @@ -384,6 +384,7 @@ Makefile.am-stamp # /src/binding/ /src/binding/c/c_binding.c +/src/binding/c/io.c # /src/binding/cxx/ /src/binding/cxx/Makefile.sm diff --git a/maint/gen_binding_c.py b/maint/gen_binding_c.py index 81977f846a0..0a4a3adbccd 100644 --- a/maint/gen_binding_c.py +++ b/maint/gen_binding_c.py @@ -19,9 +19,6 @@ def main(): abi_dir = "src/binding/abi" func_list = load_C_func_list(binding_dir) - io_func_list = [f for f in func_list if f['dir'] == 'io'] - func_list = [f for f in func_list if f['dir'] != 'io'] - # -- Loading extra api prototypes (needed until other `buildiface` scripts are updated) G.mpi_declares = [] @@ -53,6 +50,10 @@ def main(): repl_func['_replaces'].append(func) + # We generate io functions separately for now + io_func_list = [f for f in func_list if f['dir'] == 'io'] + func_list = [f for f in func_list if f['dir'] != 'io'] + # -- Generating code -- G.doc3_src_txt = [] G.poly_aliases = [] # large-count mansrc aliases @@ -144,9 +145,23 @@ def dump_c_binding_abi(): G.check_write_path(abi_file_path) dump_c_file(abi_file_path, G.out) + def dump_io_funcs(): + G.out = [] + G.out.append("#include \"mpiimpl.h\"") + G.out.append("#include \"mpir_io_impl.h\"") + G.out.append("") + + for func in io_func_list: + G.err_codes = {} + manpage_out = [] + dump_func(func, manpage_out) + + dump_out(c_dir + "/io.c") + # ---- dump_c_binding() dump_c_binding_abi() + dump_io_funcs() if 'output-mansrc' in G.opts: f = c_dir + '/mansrc/' + 'poly_aliases.lst' @@ -160,6 +175,7 @@ def dump_c_binding_abi(): G.check_write_path("src/include/mpi_proto.h") dump_Makefile_mk("%s/Makefile.mk" % c_dir) dump_mpir_impl_h("src/include/mpir_impl.h") + dump_mpir_io_impl_h("src/include/mpir_io_impl.h") dump_errnames_txt("%s/errnames.txt" % c_dir) dump_qmpi_register_h("src/mpi_t/qmpi_register.h") dump_mpi_proto_h("src/include/mpi_proto.h") diff --git a/maint/local_python/__init__.py b/maint/local_python/__init__.py index 08c41ff53c2..6a025b387da 100644 --- a/maint/local_python/__init__.py +++ b/maint/local_python/__init__.py @@ -62,6 +62,7 @@ def check_write_path(path): mpi_sources = [] mpi_declares = [] impl_declares = [] + io_impl_declares = [] mpi_errnames = [] mpix_symbols = {} diff --git a/maint/local_python/binding_c.py b/maint/local_python/binding_c.py index 24120403c33..e25a86eb9a8 100644 --- a/maint/local_python/binding_c.py +++ b/maint/local_python/binding_c.py @@ -208,6 +208,35 @@ def dump_mpix_symbols(): print("", file=Out) print("#endif /* MPIR_IMPL_H_INCLUDED */", file=Out) +def dump_mpir_io_impl_h(f): + print(" --> [%s]" %f) + with open(f, "w") as Out: + for l in G.copyright_c: + print(l, file=Out) + print("#ifndef MPIR_IO_IMPL_H_INCLUDED", file=Out) + print("#define MPIR_IO_IMPL_H_INCLUDED", file=Out) + + print("", file=Out) + print("#define MPIR_ERR_RECOVERABLE 0", file=Out) + print("#define MPIR_ERR_FATAL 1", file=Out) + print("int MPIR_Err_create_code(int, int, const char[], int, int, const char[], const char[], ...);", file=Out) + print("void MPIR_Ext_cs_enter(void);", file=Out) + print("void MPIR_Ext_cs_exit(void);", file=Out) + print("#ifndef HAVE_ROMIO", file=Out) + print("int MPIR_Err_return_comm(void *, const char[], int);", file=Out) + print("#define MPIO_Err_return_file(fh, errorcode) MPIR_Err_return_comm((void *)0, __func__, errorcode)", file=Out) + print("#else", file=Out) + print("MPI_Fint MPIR_File_c2f_impl(MPI_File fh);", file=Out) + print("MPI_File MPIR_File_f2c_impl(MPI_Fint fh);", file=Out) + print("int MPIO_Err_return_file(MPI_File fh, int errorcode);", file=Out) + print("#endif", file=Out) + + print("", file=Out) + for l in G.io_impl_declares: + print(l, file=Out) + print("", file=Out) + print("#endif /* MPIR_IO_IMPL_H_INCLUDED */", file=Out) + def filter_out_abi(): funcname = None for l in G.out: @@ -552,8 +581,10 @@ def process_func_parameters(func): do_handle_ptr = 0 (kind, name) = (p['kind'], p['name']) - if '_has_comm' not in func and kind == "COMMUNICATOR" and p['param_direction'] == 'in': + if '_has_comm' not in func and kind == "COMMUNICATOR" and p['param_direction'] == 'in' and func['name'] != "MPI_File_open": func['_has_comm'] = name + elif kind == "FILE" and p['param_direction'] == 'in' and func['dir'] == 'io': + func['_has_file'] = name elif name == "win": func['_has_win'] = name elif name == "session": @@ -733,7 +764,7 @@ def process_func_parameters(func): elif RE.match(r'F90_(COMM|ERRHANDLER|FILE|GROUP|INFO|MESSAGE|OP|REQUEST|SESSION|DATATYPE|WIN)', kind): # no validation for these kinds pass - elif RE.match(r'(POLY)?(DTYPE_STRIDE_BYTES|DISPLACEMENT_AINT_COUNT)$', kind): + elif RE.match(r'(POLY)?(DTYPE_STRIDE_BYTES|DISPLACEMENT_AINT_COUNT|OFFSET)$', kind): # e.g. stride in MPI_Type_vector, MPI_Type_create_resized pass elif is_pointer_type(p): @@ -741,7 +772,11 @@ def process_func_parameters(func): else: print("Missing error checking: func=%s, name=%s, kind=%s" % (func_name, name, kind), file=sys.stderr) - if do_handle_ptr == 1: + if func['dir'] == 'io': + # pass io function parameters as is + impl_arg_list.append(name) + impl_param_list.append(get_impl_param(func, p)) + elif do_handle_ptr == 1: if p['param_direction'] == 'inout': # assume only one such parameter func['_has_handle_inout'] = p @@ -1387,6 +1422,25 @@ def check_large_parameters(func): func['_poly_in_list'].append(p) def dump_function_normal(func): + def dump_global_cs_enter(): + if not '_skip_global_cs' in func: + G.out.append("") + if func['dir'] == 'mpit': + G.out.append("MPIR_T_THREAD_CS_ENTER();") + elif func['dir'] == 'io': + G.out.append("MPIR_Ext_cs_enter();") + else: + G.out.append("MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);") + def dump_global_cs_exit(): + if not '_skip_global_cs' in func: + G.out.append("") + if func['dir'] == 'mpit': + G.out.append("MPIR_T_THREAD_CS_EXIT();") + elif func['dir'] == 'io': + G.out.append("MPIR_Ext_cs_exit();") + else: + G.out.append("MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);") + # ---- G.out.append("int mpi_errno = MPI_SUCCESS;") if '_handle_ptr_list' in func: for p in func['_handle_ptr_list']: @@ -1405,12 +1459,7 @@ def dump_function_normal(func): else: G.out.append("MPIR_ERRTEST_INITIALIZED_ORDIE();") - if not '_skip_global_cs' in func: - G.out.append("") - if func['dir'] == 'mpit': - G.out.append("MPIR_T_THREAD_CS_ENTER();") - else: - G.out.append("MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);") + dump_global_cs_enter() G.out.append("MPIR_FUNC_TERSE_ENTER;") if '_handle_ptr_list' in func: @@ -1476,8 +1525,19 @@ def dump_function_normal(func): G.out.append("goto fn_exit;") dump_if_close() + need_endif = False + if func['dir'] == 'io' and not 'return' in func: + G.out.append("#ifndef HAVE_ROMIO") + G.out.append("mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, __func__, __LINE__, MPI_ERR_OTHER, \"**notimpl\", 0);") + G.out.append("goto fn_fail;") + G.out.append("#else") + need_endif = True + dump_body_of_routine(func) + if need_endif: + G.out.append("#endif") + G.out.append("/* ... end of body of routine ... */") # ---- @@ -1486,12 +1546,8 @@ def dump_function_normal(func): for l in func['_clean_up']: G.out.append(l) G.out.append("MPIR_FUNC_TERSE_EXIT;") + dump_global_cs_exit() - if not '_skip_global_cs' in func: - if func['dir'] == 'mpit': - G.out.append("MPIR_T_THREAD_CS_EXIT();") - else: - G.out.append("MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);") G.out.append("return mpi_errno;") G.out.append("") G.out.append("fn_fail:") @@ -1635,7 +1691,10 @@ def push_impl_decl(func, impl_name=None): mpir_name = re.sub(r'^MPIX?_', 'MPIR_', func['name']) G.impl_declares.append("int %s(%s);" % (mpir_name, params)) # dump MPIR_Xxx_impl(...) - G.impl_declares.append("int %s(%s);" % (impl_name, params)) + if func['dir'] == 'io': + G.io_impl_declares.append("int %s(%s);" % (impl_name, params)) + else: + G.impl_declares.append("int %s(%s);" % (impl_name, params)) def push_threadcomm_impl_decl(func): impl_name = re.sub(r'^mpix?_(comm_)?', 'MPIR_Threadcomm_', func['name'].lower()) @@ -2002,6 +2061,8 @@ def dump_mpi_fn_fail(func): G.out.append("mpi_errno = MPIR_Err_return_comm(%s_ptr, __func__, mpi_errno);" % func['_has_comm']) elif '_has_win' in func: G.out.append("mpi_errno = MPIR_Err_return_win(win_ptr, __func__, mpi_errno);") + elif '_has_file' in func: + G.out.append("mpi_errno = MPIO_Err_return_file(%s, mpi_errno);" % func['_has_file']) elif RE.match(r'mpi_session_init', func['name'], re.IGNORECASE): G.out.append("mpi_errno = MPIR_Err_return_session_init(errhandler_ptr, __func__, mpi_errno);") elif '_has_session' in func: @@ -2010,6 +2071,8 @@ def dump_mpi_fn_fail(func): G.out.append("mpi_errno = MPIR_Err_return_comm_create_from_group(errhandler_ptr, __func__, mpi_errno);") elif '_has_group' in func: G.out.append("mpi_errno = MPIR_Err_return_group(%s_ptr, __func__, mpi_errno);" % func['_has_group']) + elif re.match(r'MPI_File_(delete|open|close)', func['name']): + G.out.append("mpi_errno = MPIO_Err_return_file(MPI_FILE_NULL, mpi_errno);") else: G.out.append("mpi_errno = MPIR_Err_return_comm(0, __func__, mpi_errno);") @@ -2034,9 +2097,9 @@ def get_fn_fail_create_code(func): fmt = 'p' elif kind in fmt_codes: fmt = fmt_codes[kind] - elif mapping[kind] == "int": + elif mapping[kind] == "int" or mapping[kind] == "MPI_Fint": fmt = 'd' - elif mapping[kind] == "MPI_Aint": + elif mapping[kind] == "MPI_Aint" or mapping[kind] == "MPI_Offset": fmt = 'L' elif mapping[kind] == "MPI_Count": fmt = 'c' diff --git a/src/binding/abi/Makefile.mk b/src/binding/abi/Makefile.mk index 197a48e3c19..199d860b5e9 100644 --- a/src/binding/abi/Makefile.mk +++ b/src/binding/abi/Makefile.mk @@ -9,6 +9,7 @@ include_HEADERS += src/binding/abi/mpi_abi.h mpi_abi_sources += \ src/binding/abi/mpi_abi_util.c \ - src/binding/abi/c_binding_abi.c + src/binding/abi/c_binding_abi.c \ + src/binding/abi/io_abi.c endif BUILD_ABI_LIB From eaebe60f8183d2f701b660bbc16ba446d72e53b9 Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Thu, 5 Dec 2024 22:16:47 -0600 Subject: [PATCH 12/13] binding/python: generate io abi bindings Because ROMIO is built on top of the rest of MPI, it is difficult to use the abi wrappers because we need either - a. convert from ABI into MPICH abi and then convert back to ABI before calling into ROMIO. This seems silly. Or - b. build ROMIO on MPICH abi. But in libmpi_abi.so, MPICH abi is not available. Thus we need - c. Switch ROMIO to call MPICH impl functions instead of `MPI/PMPI` functions. We'll need to build a layer in ROMIO switch between using `MPI/PMPI` or using `MPIR_Xxx_impl` depending on build options. This will result in ROMIO having full access to MPICH internals! But let's delay work until we have a convincing need. Thus, this commit implements io abi bindings without the abi wrappers. We implemented a separate path rather than making the existing code more complex. --- maint/gen_abi.py | 49 ++++++++++++++++++++++++- maint/gen_binding_c.py | 16 +++++++++ maint/local_python/binding_c.py | 63 ++++++++++++++++++++++++++++++--- 3 files changed, 122 insertions(+), 6 deletions(-) diff --git a/maint/gen_abi.py b/maint/gen_abi.py index d449339aabd..826bc747b94 100644 --- a/maint/gen_abi.py +++ b/maint/gen_abi.py @@ -25,6 +25,7 @@ def search(pat, str, flags=0): def main(): load_mpi_abi_h("src/binding/abi/mpi_abi.h") dump_mpi_abi_internal_h("src/binding/abi/mpi_abi_internal.h") + dump_io_abi_internal_h("src/binding/abi/io_abi_internal.h") dump_romio_abi_internal_h("src/mpi/romio/include/romio_abi_internal.h") dump_mpi_abi_util_c("src/binding/abi/mpi_abi_util.c") @@ -101,7 +102,7 @@ def gen_mpi_abi_internal_h(out): for line in output_lines: print(line, file=Out) print("", file=Out) - + print("#endif /* MPI_ABI_INTERNAL_H_INCLUDED */", file=Out) def dump_romio_abi_internal_h(romio_abi_internal_h): @@ -181,6 +182,52 @@ def add_other(out): print("#define ROMIO_ABI_INTERNAL_H_INCLUDED", file=Out) print("", file=Out) + for line in output_lines: + print(line, file=Out) + print("", file=Out) + + print("#endif /* ROMIO_ABI_INTERNAL_H_INCLUDED */", file=Out) + +# similar to romio_abi_internal.h but for use in the mpich io binding +def dump_io_abi_internal_h(io_abi_internal_h): + def gen_io_abi_internal_h(out): + for line in G.abi_h_lines: + if RE.search(r'MPI_ABI_H_INCLUDED', line): + # skip the include guard, harmless + pass + elif RE.match(r'typedef struct.*\bMPI_File;\s*$', line): + out.append("typedef struct ADIOI_FileD *MPI_File;") + elif RE.match(r'(int|double|MPI_\w+) (P?MPI\w+)\((.*)\);', line): + # prototypes, rename param prefix, add MPICH_API_PUBLIC + (T, name, param) = RE.m.group(1,2,3) + if RE.match(r'P?MPI_(File_\w+|Register_datarep\w*)', name): + out.append("%s %s(%s) MPICH_API_PUBLIC;" % (T, name, param)) + else: + out.append("%s %s(%s);" % (T, name, param)) + else: + # replace param prefix + out.append(line.rstrip()) + + def add_mpich_visibility(out): + out.append("#if defined(HAVE_VISIBILITY)") + out.append("#define MPICH_API_PUBLIC __attribute__((visibility (\"default\")))") + out.append("#else") + out.append("#define MPICH_API_PUBLIC") + out.append("#endif") + out.append("") + + # ---- + output_lines = [] + add_mpich_visibility(output_lines) + gen_io_abi_internal_h(output_lines) + + print(" --> [%s]" % io_abi_internal_h) + with open(io_abi_internal_h, "w") as Out: + dump_copyright(Out) + print("#ifndef ROMIO_ABI_INTERNAL_H_INCLUDED", file=Out) + print("#define ROMIO_ABI_INTERNAL_H_INCLUDED", file=Out) + print("", file=Out) + for line in output_lines: print(line, file=Out) print("", file=Out) diff --git a/maint/gen_binding_c.py b/maint/gen_binding_c.py index 0a4a3adbccd..ccb37681a2b 100644 --- a/maint/gen_binding_c.py +++ b/maint/gen_binding_c.py @@ -158,10 +158,26 @@ def dump_io_funcs(): dump_out(c_dir + "/io.c") + def dump_io_funcs_abi(): + G.out = [] + G.out.append("#include \"mpichconf.h\"") + G.out.append("#include \"io_abi_internal.h\"") + G.out.append("#include \"mpir_io_impl.h\"") + G.out.append("#include ") + G.out.append("") + + for func in io_func_list: + dump_func_abi(func) + + abi_file_path = abi_dir + "/io_abi.c" + G.check_write_path(abi_file_path) + dump_c_file(abi_file_path, G.out) + # ---- dump_c_binding() dump_c_binding_abi() dump_io_funcs() + dump_io_funcs_abi() if 'output-mansrc' in G.opts: f = c_dir + '/mansrc/' + 'poly_aliases.lst' diff --git a/maint/local_python/binding_c.py b/maint/local_python/binding_c.py index e25a86eb9a8..773b16bc8fd 100644 --- a/maint/local_python/binding_c.py +++ b/maint/local_python/binding_c.py @@ -81,14 +81,18 @@ def dump_romio_reference(name): dump_profiling(func) - if 'polymorph' in func: + skip_wrappers = False + if func['dir'] == 'io' and '_is_abi' in func: + # The mpi-abi version of io bindings does not have access to MPICH internals (i.e. mpiimpl.h) + dump_function_io(func) + skip_wrappers = True + elif 'polymorph' in func: # MPII_ function to support C/Fortran Polymorphism, eg MPI_Comm_get_attr G.out.append("#ifndef MPICH_MPI_FROM_PMPI") dump_function_internal(func, kind="polymorph") G.out.append("#endif /* MPICH_MPI_FROM_PMPI */") G.out.append("") - if 'polymorph' in func: dump_function_internal(func, kind="call-polymorph") elif 'replace' in func and 'body' not in func: pass @@ -96,7 +100,9 @@ def dump_romio_reference(name): dump_function_internal(func, kind="normal") G.out.append("") - if '_is_abi' in func: + if skip_wrappers: + pass + elif '_is_abi' in func: dump_abi_wrappers(func, func['_is_large']) else: # Create the MPI and QMPI wrapper functions that will call the above, "real" version of the @@ -215,15 +221,20 @@ def dump_mpir_io_impl_h(f): print(l, file=Out) print("#ifndef MPIR_IO_IMPL_H_INCLUDED", file=Out) print("#define MPIR_IO_IMPL_H_INCLUDED", file=Out) - print("", file=Out) + + # io_abi.c doesn't have access to MPICH internal + print("#ifdef BUILD_MPI_ABI", file=Out) print("#define MPIR_ERR_RECOVERABLE 0", file=Out) print("#define MPIR_ERR_FATAL 1", file=Out) print("int MPIR_Err_create_code(int, int, const char[], int, int, const char[], const char[], ...);", file=Out) + print("int MPIR_Err_return_comm(void *, const char[], int);", file=Out) + print("#endif", file=Out) + print("", file=Out) + print("void MPIR_Ext_cs_enter(void);", file=Out) print("void MPIR_Ext_cs_exit(void);", file=Out) print("#ifndef HAVE_ROMIO", file=Out) - print("int MPIR_Err_return_comm(void *, const char[], int);", file=Out) print("#define MPIO_Err_return_file(fh, errorcode) MPIR_Err_return_comm((void *)0, __func__, errorcode)", file=Out) print("#else", file=Out) print("MPI_Fint MPIR_File_c2f_impl(MPI_File fh);", file=Out) @@ -845,6 +856,48 @@ def dump_copy_right(): G.out.append(" */") G.out.append("") +def dump_function_io(func): + is_large = func['_is_large'] + parameters = "" + for p in func['c_parameters']: + parameters = parameters + ", " + p['name'] + + func_decl = get_declare_function(func, is_large) + + dump_line_with_break(func_decl) + G.out.append("{") + G.out.append("INDENT") + if "impl" in func and func['impl'] == "direct": + dump_function_direct(func) + else: + G.out.append("int mpi_errno = MPI_SUCCESS;") + if not '_skip_global_cs' in func: + G.out.append("MPIR_Ext_cs_enter();") + G.out.append("") + G.out.append("#ifndef HAVE_ROMIO") + if not '_is_abi' in func: + G.out.append("mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__, MPI_ERR_OTHER, \"**notimpl\", 0);") + else: + G.out.append("mpi_errno = MPI_ERR_INTERN;") + G.out.append("goto fn_fail;"); + G.out.append("#else") + dump_body_of_routine(func) + G.out.append("#endif") + G.out.append("") + G.out.append("fn_exit:") + if not '_skip_global_cs' in func: + G.out.append("MPIR_Ext_cs_exit();") + G.out.append("return mpi_errno;") + G.out.append("fn_fail:") + if '_has_file' in func: + G.out.append("mpi_errno = MPIO_Err_return_file(%s, mpi_errno);" % func['_has_file']) + else: + G.out.append("mpi_errno = MPIO_Err_return_file(MPI_FILE_NULL, mpi_errno);") + G.out.append("goto fn_exit;") + G.out.append("DEDENT") + G.out.append("}") + G.out.append("") + def dump_qmpi_wrappers(func, is_large): parameters = "" for p in func['c_parameters']: From ca0ea65513d63e849b652ce7d807768f346d6094 Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Thu, 9 Jan 2025 11:38:38 -0600 Subject: [PATCH 13/13] abi: call ABI_init_builtins in MPI_T_init_thread The MPI datatype constants are needed for loading some of the cvar environment variables. This fixes the abi tests using the run_mpitests facility. --- maint/local_python/binding_c.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maint/local_python/binding_c.py b/maint/local_python/binding_c.py index 773b16bc8fd..e1ea7fe68d5 100644 --- a/maint/local_python/binding_c.py +++ b/maint/local_python/binding_c.py @@ -1194,7 +1194,7 @@ def out_can_be_undefined(p): G.out.append("int ret = " + static_call + ";") for l in post_filters: G.out.append(l) - if re.match(r'MPI_(Init|Init_thread|Session_init)$', func_name, re.IGNORECASE): + if re.match(r'MPI_(Init|Init_thread|Session_init|T_init_thread)$', func_name, re.IGNORECASE): G.out.append("ABI_init_builtins();") G.out.append("return ret;") G.out.append("DEDENT")