Regenerate the API against MPI 5.0, and add the large-count entry points - #990
Merged
Merged
Conversation
src/api/generated_api.jl was last regenerated in 2022 from MPICH 4.0 headers, so the
bindings covered MPI 4.0. Regenerate from MPICH 5.0: 29 procedures added (the MPI 4.1
buffer-attach, MPI_Status_get_*/set_* and MPI_Request_get_status_* families,
MPI_Type_get_value_index, MPI_Get_hw_resource_info, MPI_Remove_error_*, and MPI 5.0's
MPI_Abi_*), 2 removed.
gen/ is reworked so this is reproducible. gen.sh followed whatever MPIPreferences the
surrounding environment resolved to -- which need not even be a supported source -- so
pin the choice before Pkg runs, since MPICH_jll's platform augmentation consults it at
resolve time; and drop a stale gen/Manifest.toml, which is not committed and so is not
what makes this reproducible, but whose reuse silently generates against the wrong MPI
version. Clang.jl drives the formatting of the whole output file and only runs on
Julia 1.10, so both are pinned. The instructions now live at the top of gen.sh, since
regenerating is a deliberate act rather than something CI should enforce.
@mpichk now always probes for the symbol, not just for the eight procedures that
happened to carry a minimum version, so the whole MPI 4.1/5.0 surface degrades to a
FeatureLevelError rather than an unresolved symbol. min_version is
Union{Nothing,VersionNumber}: procedures predating MPI 3.1 get none, since MPI.jl
requires MPI 3.0 anyway and there is no public machine-readable way to separate 1.0
through 3.1. The version table itself is derived from the MPI standard's own
machine-readable bindings rather than hand-listed; see gen/versions/README.md.
The 155 large-count MPI_*_c entry points become usable from any supported library:
where one does not provide them, each falls back to its narrow counterpart, so a
caller names a single entry point everywhere and an over-large count raises
InexactError instead of being truncated. That is all-or-nothing, because API.Count,
API.Displ and API.TypeDispl are a single choice for the whole package and an
implementation may ship only part of the set -- Intel MPI 2021.11 has MPI_Send_c but
not MPI_Type_size_c, and deciding per function let a Ref{MPI_Count} reach an entry
point wanting a Ptr{Cint}. MPI_Op_create_c and MPI_Register_datarep_c are excluded
from the fallback: their callback's len argument widens with the counts, so swapping
the creators would read it at the wrong width.
Nothing above src/api/ uses any of this yet; that follows separately.
Two fixes fall out. MPI_Aint_add and MPI_Aint_diff return an MPI_Aint, not an error
code, but were wrapped in @mpichk, so any nonzero result was thrown as an MPIError;
error checking is now derived from the ccall return type rather than a hand-kept list.
And the handle conversions are ignored rather than generated: they return a handle,
which @mpichk would likewise mistake for an errcode, and api.jl writes them by hand.
MPICH's docs have caught up since the comment in _doc_external was written, so point
the generated man-page links at the current release rather than v4.0, which has no
pages for anything added since.
giordano
reviewed
Sep 22, 2026
MPI_Pcontrol can be called, so make it callable. My ignorelist entry claimed Clang's rendering was not usable from Julia, which was wrong twice over: Clang.jl does not generate a wrapper for a variadic declaration at all, so the entry never did anything, and the procedure is perfectly callable. It is the MPI C API's only variadic procedure, so write it by hand in src/api/api.jl alongside the handle conversions. The arguments after `level` are implementation-defined and are not exposed; passing none means the call needs no variadic argument passing, so it goes through the ordinary `@mpichk` path, which also keeps a profiler able to intercept it -- the whole point of this one. test_featurelevel.jl now calls it, so every CI configuration exercises it. Pin the generated man-page links. "latest" and "main" move under us, so links written today silently rot. MPICH's tree is pinned to v5.0.1, the version the bindings are generated from, which documents every procedure here. Open MPI is pinned to v5.0.x, which documents MPI 4.0 and earlier but neither the large-count `_c` procedures nor anything added in 4.1 -- so `_doc_external` now takes the introducing MPI version and links to Open MPI only where it has a page. The generator passes that version through from the same INTRODUCED table it already uses for the feature-level gating. Checked a sample from each category -- pre-3.1, 4.0, 4.1+, and `_c` -- and every resulting URL resolves.
giordano
reviewed
Sep 22, 2026
CI showed the previous commit's MPI_Pcontrol crashing: Intel MPI 2019.9 and 2021.11 segfaulted, and all three 32-bit Windows jobs died with 0xC0000005. I had claimed that passing no variadic argument made a plain non-variadic call safe. It does not. On x86-64 System V a variadic callee reads `al` for the number of vector registers used, which a non-variadic call never sets, so `va_start` spills against garbage. On 32-bit Windows a variadic function is `cdecl` even though the rest of MS-MPI is `stdcall`, so `@mpicall`'s `stdcall` fixup corrupts the stack. Use `@ccall`'s `;` form, which emits a genuinely variadic call, with the bare symbol name on Unix so that an `LD_PRELOAD` profiler can still intercept it. Both crash modes are recorded in the docstring, since the code looks needlessly elaborate without them. Also from review: The ignorelist comment claimed these were "not a C binding MPI.jl can call", which described nothing -- `MPI_T_*`, `MPI_Session_*` and the Fortran 2008 status conversions are all callable C functions. Say what the group actually is: parts of MPI that MPI.jl does not wrap, plus the profiling and vendor-extension prefixes. The two manual-page URL bases were module-level constants used by one function and never at run time, since the docstrings are built during precompilation. They are locals in `_doc_external` now.
giordano
added this pull request to stack #992
September 23, 2026 13:27
giordano
approved these changes
Sep 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the first part of #989 (large count functions).
Update the API generator to handle MPI 4.0, 4.1, and 5.0. This is mainly a mechanical change.
The large-count function (e.g. MPI_Send_c) take a 64-bit count argument whereas the narrow functions (e.g. MPI_Send) only take a 32-bit count. On a 64-bit system, 64-bit counts are clearly desirable.
To handle older MPI libraries which do not provide the large-count functions, I decided to do this in the code generator: The large-count functions (MPI_Send_c) are always provided. If the MPI library provides them, they are called. If not – and that is known at precompile time – then the narrow function (MPI_Send) is called instead. This means that the high-level functions do not need to care about this distinction, they can always call the large-count functions. The type conversion for counts (from Int to either Int64 or Cint) are handled by @CCall, efficiently, without a run-time check. Using a count argument that is too large for the MPI library throws an error.
This PR only regenerates the bindings. Existing code should not see any change in behaviour yet.