External libraries and packages
Other libraries and packages may also make use of MPI. There are several concerns to ensure things are set up correctly.
Binary requirements
You need to ensure that external libraries are built correctly. In particular, if you are using a system-provided MPI backend in Julia, you also need to use the same system-provided binary for all packages and external libraries you use.
Passing MPI handles via ccall
When passing MPI.jl handle objects (MPI.Comm
, MPI.Info
, etc) to C/C++ functions via ccall
, you should pass the object directly as an argument, and specify the argument type as either the underlying handle type (MPI.MPI_Comm
, MPI.MPI_Info
, etc.), or a pointer (Ptr{MPI.MPI_Comm}
, Ptr{MPI.MPI_Info}
, etc.). This will internally handle the unwrapping, but ensure that a reference is kept to avoid premature garbage collection.
For example the C function signatures
int cfunc1(MPI_Comm comm);
int cfunc2(MPI_Comm * comm);
would be called as
ccall((:cfunc1, lib), Cint, (MPI.MPI_Comm,), comm)
ccall((:cfunc2, lib), Cint, (Ptr{MPI.MPI_Comm},), comm)
Object finalizers and MPI.Finalize
External libraries may allocate their own MPI handles (e.g., create or duplicate MPI communicators), which need to be cleaned up before MPI is finalized. If these are attached to object finalizers, they may not be guaranteed to be called before MPI.Finalize
, which can result in an error upon program exit. (By default, MPI.jl will install an atexit
hook that calls MPI.Finalize
if it hasn't already been invoked.)
There are two typical solutions to this problem:
Gate the clean up functions behind an
MPI.Finalized
call, e.g.finalizer(obj) do obj if !MPI.Finalized # call clean up function end end
Keep track of all such objects, clean them up via
MPI.add_finalize_hook!
, e.g.finalizer(obj) do obj # call clean up function end MPI.add_finalize_hook!(() -> finalize(obj))
A variant of this is to keep track of all such objects, for example, using a
WeakKeyDict
, and use a hook to clean them all:const REFS = WeakKeyDict{ObjType, Nothing}() MPI.add_finalize_hook!() do for obj in keys(REFS) finalize(obj) end end # for each object `obj` finalizer(obj) do obj # call clean up function end REFS[obj] = nothing
Externally initialized MPI
When working with non-Julia libraries or tools, MPI_Init
may be invoked in another part of the execution flow and not via MPI.jl's MPI.Init
function. This leaves some package-internal settings uninitialized. In this case, you need to call MPI.run_init_hooks()
manually to fully initialize MPI.jl. You may also want to consider calling MPI.set_default_error_handler_return()
.