Skip to content

Commit

Permalink
binding/python: generate io abi bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
hzhou committed Dec 6, 2024
1 parent 13eaeb3 commit 3c43546
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 48 deletions.
49 changes: 48 additions & 1 deletion maint/gen_abi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -187,6 +188,52 @@ def add_other(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)

print("#endif /* ROMIO_ABI_INTERNAL_H_INCLUDED */", file=Out)

def dump_mpi_abi_util_c(mpi_abi_util_c):
def dump_init_once(Out):
print(" static int initialized = 0;", file=Out)
Expand Down
50 changes: 22 additions & 28 deletions maint/gen_binding_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,46 +145,39 @@ def dump_c_binding_abi():
G.check_write_path(abi_file_path)
dump_c_file(abi_file_path, G.out)

def dump_io_funcs(do_abi=False):
def dump_io_funcs():
G.io_impl_declares = []
G.out = []
G.out.append("#include \"mpiimpl.h\"")
if do_abi:
G.out.append("#include \"mpi_abi_util.h\"")
G.out.append("#include \"mpir_io_impl.h\"")
G.out.append("")
# Add a couple direct impl prototypes
G.out.append("void MPIR_Ext_cs_enter(void);")
G.out.append("void MPIR_Ext_cs_exit(void);")
G.out.append("#ifndef HAVE_ROMIO")
G.out.append("#define MPIO_Err_return_file(fh, errorcode) MPIR_Err_return_comm(0, __func__, errorcode)")
G.out.append("#else")
G.out.append("MPI_Fint MPIR_File_c2f_impl(MPI_File fh);")
G.out.append("MPI_File MPIR_File_f2c_impl(MPI_Fint fh);")
G.out.append("int MPIO_Err_return_file(MPI_File fh, int errorcode);")
G.out.append("#endif")

G.doc3_src_txt = []
G.poly_aliases = [] # large-count mansrc aliases

for func in io_func_list:
G.err_codes = {}
manpage_out = []
if not do_abi:
dump_func(func, manpage_out)
else:
dump_func_abi(func)

if not do_abi:
dump_out(c_dir + "/io.c")
else:
abi_file_path = abi_dir + "/io_abi.c"
G.check_write_path(abi_file_path)
dump_c_file(abi_file_path, G.out)
dump_func(func, manpage_out)

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("")

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(True)
dump_io_funcs_abi()

if 'output-mansrc' in G.opts:
f = c_dir + '/mansrc/' + 'poly_aliases.lst'
Expand All @@ -198,6 +191,7 @@ def dump_io_funcs(do_abi=False):
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")
Expand Down
115 changes: 96 additions & 19 deletions maint/local_python/binding_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,27 +82,30 @@ def dump_romio_reference(name):

dump_profiling(func)

if '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
if func['dir'] == 'io':
dump_function_io(func)
else:
dump_function_internal(func, kind="normal")
G.out.append("")
if '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 '_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
# function in the internal prefix
dump_qmpi_wrappers(func, func['_is_large'])
if 'polymorph' in func:
dump_function_internal(func, kind="call-polymorph")
elif 'replace' in func and 'body' not in func:
pass
else:
dump_function_internal(func, kind="normal")
G.out.append("")

if '_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
# function in the internal prefix
dump_qmpi_wrappers(func, func['_is_large'])

def get_func_file_path(func, root_dir):
file_path = None
Expand Down Expand Up @@ -209,6 +212,32 @@ 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("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:
Expand Down Expand Up @@ -823,6 +852,54 @@ 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)
func_name = get_function_name(func, is_large)
# declare impl functions, but only do it once
if '_is_abi' not in func and 'return' not in func:
if func['_is_large'] and func['_poly_impl'] != "separate":
pass
else:
impl_name = re.sub(r'^MPIX?_', 'MPIR_', func['name']) + "_impl"
if func['_is_large'] and func['_poly_impl'] == "separate":
impl_name = re.sub(r'_impl$', '_large_impl', impl_name)
if func['_impl_param_list']:
params = ', '.join(func['_impl_param_list'])
else:
params="void"
G.io_impl_declares.append("int %s(%s);" % (impl_name, params))

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("")
dump_body_impl(func)
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']:
Expand Down

0 comments on commit 3c43546

Please sign in to comment.