Skip to content

Add package extension for MPI.jl - #198

Merged
giordano merged 4 commits into
JuliaArrays:mainfrom
vchuravy:vc/mpi-ext
Oct 13, 2026
Merged

giordano merged 4 commits into
JuliaArrays:mainfrom
vchuravy:vc/mpi-ext

Conversation

@vchuravy

Copy link
Copy Markdown
Contributor

This adds a package extension for MPI.jl, so that FixedSizeArrays, and SubArrays of them, can be used directly as communication buffers (MPI.Send, MPI.Recv!, MPI.Bcast!, MPI.Gatherv!, MPI.Allreduce!, ...).

Motivation

Trixi.jl is replacing unsafe_wrap(Array, pointer(v), dims) views of resize!able vectors with FixedSizeArrays.wrap(FixedSizeArray, v, dims) (#196). Some of those arrays are passed to MPI. With the released MPI.jl (v0.20.27):

  • MPI.Buffer has methods only for Array, Ref and some SubArrays, so e.g. MPI.Gatherv!(vec(a[1, .., :]), ...) or MPI.Send(a, ...) with a FixedSizeArray throws a MethodError.
  • Base.cconvert(MPI.MPIPtr, x) is defined only for Ptr, Array, Ref and SubArray. A non-fast SubArray (e.g. view(a, 1:1, 2:3, :)) is sent with a subarray datatype, and MPI.Buffer stores its parent, which then also fails for a FixedSizeArray parent.

What the extension defines

All methods involve FixedSizeArray, so there is no type piracy.

  • Base.cconvert(::Type{MPIPtr}, a) and Base.unsafe_convert(::Type{MPIPtr}, a) for FixedSizeArrays backed by host memory (Vector, and Memory on Julia v1.11+). cconvert returns the FixedSizeArray itself, which ccall keeps rooted and which keeps its parent alive. Delegating to the parent does not work here, since MPI.jl v0.20.27 has no MPIPtr conversion for Memory, the default storage type.
  • For any other storage type (e.g. GPU arrays), cconvert delegates to the parent, so MPI.jl's own support for that array type is used.
  • MPI.Buffer(a::FixedSizeArray), sending length(a) elements of MPI.Datatype(eltype(a)).

UBuffer, VBuffer and RBuffer already accept any AbstractArray with unit stride, so they need nothing extra.

Relation to MPI.jl upstream

MPI.jl master (unreleased, JuliaParallel/MPI.jl#941) makes the MPIPtr conversion generic for AbstractArrays, but MPI.Buffer is still Array-only there. I'm opening a draft PR to MPI.jl to accept any DenseArray in MPI.Buffer (link to follow). This extension is still needed for all released MPI v0.20.x, and its methods are strictly more specific than the upstream ones, so it stays correct afterwards. The full test suite also passes against MPI.jl master.

Tests

A new "MPI" testset runs single-process (MPI.COMM_WORLD, no mpiexec), for Memory and Vector storage, element types Float64, Int, ComplexF64 and a padded isbits struct, and 1-, 2- and 3-dimensional arrays. It covers Buffer and pointer conversion, point-to-point to self, Bcast!, Gatherv!, Allgather!, Scatterv!, Allreduce!/Allreduce/Reduce! (out of place and in place), fast and non-fast strided views (send, receive into, scatter into), and delegation for a non-host DenseVector parent. Reductions are skipped for the struct type, since user-defined reduction operators are not supported on all platforms.

This adds MPI.jl (and MPICH_jll, ~30 MB) as a test dependency; the testset takes about 20 s. Happy to trim it if that's too heavy.

Locally, Pkg.test() (including Aqua) passes on Julia 1.10, 1.11, 1.12 and 1.13-rc1 with MPI.jl v0.20.27, and on Julia 1.12 with MPI.jl master. I also ran a separate 2-rank mpiexec script (Send/Recv!, non-fast views, Gatherv!, Scatterv!, Allreduce, Reduce!, Bcast! on 4-dimensional arrays) with MPI.jl v0.20.0, v0.20.27 and master; it is not part of this PR. I did not test Windows (MicrosoftMPI) or 32-bit Linux locally, and GPU-backed FixedSizeArrays are untested.

This PR was prepared with substantial assistance from Claude Code (Anthropic's AI coding assistant). I reviewed the changes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MEJYUviAUshj5fZt8LTe8A

vchuravy and others added 2 commits October 13, 2026 14:16
Define `MPI.Buffer(::FixedSizeArray)` and the conversion to `MPI.MPIPtr`, so
that `FixedSizeArray`s, and `SubArray`s of them that MPI.jl stores via their
parent, can be used as communication buffers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEJYUviAUshj5fZt8LTe8A
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEJYUviAUshj5fZt8LTe8A
@codecov

codecov Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.47%. Comparing base (b038629) to head (6b71071).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #198      +/-   ##
==========================================
+ Coverage   93.39%   93.47%   +0.08%     
==========================================
  Files           5        6       +1     
  Lines         227      230       +3     
==========================================
+ Hits          212      215       +3     
  Misses         15       15              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

On Julia v1.14, `Base.cconvert(Ptr{T}, ::SubArray)` returns a
`Base.OffsetCConvert`, which MPI.jl v0.20.27 cannot convert to an `MPIPtr`,
so views of any array (not only `FixedSizeArray`s) fail there. This is fixed
in MPI.jl by JuliaParallel/MPI.jl#941. Detect this by probing a view of an
`Array` and skip the tests of views if it fails.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEJYUviAUshj5fZt8LTe8A
Comment thread ext/FixedSizeArraysMPIExt.jl Outdated
@giordano giordano mentioned this pull request Oct 13, 2026
MPI.jl v0.20.28 (JuliaParallel/MPI.jl#941) converts any `AbstractArray` to an
`MPIPtr`, including `Memory` and `SubArray`s on Julia v1.14+, so the
host-memory `cconvert`/`unsafe_convert` methods and the view-support probe in
the tests are no longer needed. Delegating `cconvert` to the parent is kept so
that GPU-backed `FixedSizeArray`s use MPI.jl's pointer type for their storage.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
vchuravy added a commit to trixi-framework/Trixi.jl that referenced this pull request Oct 13, 2026
…zeArray`s

- `wrap_array` returns a `FixedSizeArray` (via `wrap_vector`) for `Vector`s
  and a `reshape` otherwise (GPU arrays, views), on all threading backends,
  instead of a `PtrArray` with raw pointers.
- Remove `wrap_array_native`; all callers use `wrap_array`. The DG methods of
  `wrap_array` are merged into one.
- Use `FixedSizeArray`s for all containers that wrap `resize!`able vectors
  (TreeMesh, P4est, T8code, Structured, parabolic, mesh trees).
- Remove `unsafe_wrap_or_alloc` and the GPU extension methods in favor of
  `wrap_storage`, which dispatches on the backing vector.
- Let the hand-written `@turbo` kernels dispatch on `TurboArray`
  (`PtrArray` or `FixedSizeArray` with native element types).
- Send strided views in `MPI.Gatherv!` instead of copies, which requires
  MPI.jl v0.20.28 for `SubArray`s on Julia v1.14.
- Use the MPI.jl package extension of FixedSizeArrays.jl
  (JuliaArrays/FixedSizeArrays.jl#198) via `[sources]`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEJYUviAUshj5fZt8LTe8A
Comment on lines +15 to +19
# A `FixedSizeArray` is a `DenseArray`, i.e. its elements are contiguous in memory in
# column-major order, so it can be sent as `length(a)` elements of type `eltype(a)`.
function MPI.Buffer(a::FixedSizeArray)
MPI.Buffer(a, Cint(length(a)), MPI.Datatype(eltype(a)))
end

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we could also drop this with JuliaParallel/MPI.jl#996? But ok, this shouldn't hold this PR, we can remove it afterwards.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it will still be correct after that lands.

@giordano
giordano merged commit aa3f40b into JuliaArrays:main Oct 13, 2026
18 of 33 checks passed
vchuravy added a commit to trixi-framework/Trixi.jl that referenced this pull request Oct 13, 2026
…zeArray`s

- `wrap_array` returns a `FixedSizeArray` (via `wrap_vector`) for `Vector`s
  and a `reshape` otherwise (GPU arrays, views), on all threading backends,
  instead of a `PtrArray` with raw pointers.
- Remove `wrap_array_native`; all callers use `wrap_array`. The DG methods of
  `wrap_array` are merged into one.
- Use `FixedSizeArray`s for all containers that wrap `resize!`able vectors
  (TreeMesh, P4est, T8code, Structured, parabolic, mesh trees).
- Remove `unsafe_wrap_or_alloc` and the GPU extension methods in favor of
  `wrap_storage`, which dispatches on the backing vector.
- Let the hand-written `@turbo` kernels dispatch on `TurboArray`
  (`PtrArray` or `FixedSizeArray` with native element types).
- Send strided views in `MPI.Gatherv!` instead of copies, which requires
  MPI.jl v0.20.28 for `SubArray`s on Julia v1.14.
- Use the MPI.jl package extension of FixedSizeArrays.jl
  (JuliaArrays/FixedSizeArrays.jl#198) via `[sources]`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEJYUviAUshj5fZt8LTe8A
vchuravy added a commit to trixi-framework/Trixi.jl that referenced this pull request Oct 20, 2026
…zeArray`s

- `wrap_array` returns a `FixedSizeArray` (via `wrap_vector`) for `Vector`s
  and a `reshape` otherwise (GPU arrays, views), on all threading backends,
  instead of a `PtrArray` with raw pointers.
- Remove `wrap_array_native`; all callers use `wrap_array`. The DG methods of
  `wrap_array` are merged into one.
- Use `FixedSizeArray`s for all containers that wrap `resize!`able vectors
  (TreeMesh, P4est, T8code, Structured, parabolic, mesh trees).
- Remove `unsafe_wrap_or_alloc` and the GPU extension methods in favor of
  `wrap_storage`, which dispatches on the backing vector.
- Let the hand-written `@turbo` kernels dispatch on `TurboArray`
  (`PtrArray` or `FixedSizeArray` with native element types).
- Send strided views in `MPI.Gatherv!` instead of copies, which requires
  MPI.jl v0.20.28 for `SubArray`s on Julia v1.14.
- Use the MPI.jl package extension of FixedSizeArrays.jl
  (JuliaArrays/FixedSizeArrays.jl#198) via `[sources]`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEJYUviAUshj5fZt8LTe8A
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants