From 61947d925f0b5dee1c62ed1f668a77be19ee9947 Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Fri, 30 Sep 2022 11:59:35 -0700 Subject: [PATCH] combine Consts and API modules (#650) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * combine Consts and API modules * @t-bltg's fixes * Builds docs only for functions in `API` module Co-authored-by: Mosè Giordano --- docs/src/reference/advanced.md | 2 +- docs/src/reference/api.md | 1 + gen/src/MPIgenerator.jl | 2 +- src/MPI.jl | 63 +++----- src/api/api.jl | 138 ++++++++++++++++++ .../generated_api.jl} | 0 src/{consts => api}/microsoftmpi.jl | 0 src/{consts => api}/mpich.jl | 0 src/{consts => api}/mpitrampoline.jl | 0 src/{consts => api}/mpt.jl | 0 src/{consts => api}/openmpi.jl | 0 src/buffers.jl | 2 +- src/collective.jl | 4 +- src/comm.jl | 22 +-- src/consts/consts.jl | 54 ------- src/datatypes.jl | 14 +- src/environment.jl | 16 +- src/errhandler.jl | 12 +- src/error.jl | 44 +----- src/group.jl | 24 +-- src/implementations.jl | 25 +--- src/info.jl | 12 +- src/io.jl | 32 ++-- src/misc.jl | 4 +- src/nonblocking.jl | 28 ++-- src/onesided.jl | 22 +-- src/operators.jl | 52 +++---- src/pointtopoint.jl | 14 +- src/topology.jl | 26 ++-- test/test_cart_shift.jl | 2 +- test/test_ibarrier.jl | 14 +- test/test_test.jl | 12 +- 32 files changed, 319 insertions(+), 322 deletions(-) create mode 100644 src/api/api.jl rename src/{auto_generated_api.jl => api/generated_api.jl} (100%) rename src/{consts => api}/microsoftmpi.jl (100%) rename src/{consts => api}/mpich.jl (100%) rename src/{consts => api}/mpitrampoline.jl (100%) rename src/{consts => api}/mpt.jl (100%) rename src/{consts => api}/openmpi.jl (100%) delete mode 100644 src/consts/consts.jl diff --git a/docs/src/reference/advanced.md b/docs/src/reference/advanced.md index 77cf76eca..7cdaf73b4 100644 --- a/docs/src/reference/advanced.md +++ b/docs/src/reference/advanced.md @@ -45,5 +45,5 @@ MPI.set_errorhandler! ## Miscellaneous ```@docs -MPI.Consts.@const_ref +MPI.API.@const_ref ``` diff --git a/docs/src/reference/api.md b/docs/src/reference/api.md index de4f30da8..99e886608 100644 --- a/docs/src/reference/api.md +++ b/docs/src/reference/api.md @@ -2,4 +2,5 @@ ```@autodocs Modules = [MPI.API] +Order = [:function] ``` diff --git a/gen/src/MPIgenerator.jl b/gen/src/MPIgenerator.jl index fefb24900..ed71c1621 100644 --- a/gen/src/MPIgenerator.jl +++ b/gen/src/MPIgenerator.jl @@ -80,7 +80,7 @@ module MPIgenerator end write(src, join(lines, "\n")) - dst = normpath(@__DIR__, "..", "..", "src", "auto_generated_api.jl") + dst = normpath(@__DIR__, "..", "..", "src", "api", "generated_api.jl") mv(src, dst; force=true) # move the generated file to src rm(out) # cleanup diff --git a/src/MPI.jl b/src/MPI.jl index 3d2236bfc..4c70e7fca 100644 --- a/src/MPI.jl +++ b/src/MPI.jl @@ -17,15 +17,6 @@ function deserialize(x) Serialization.deserialize(s) end -primitive type SentinelPtr Sys.WORD_SIZE -end - -primitive type MPIPtr Sys.WORD_SIZE -end -@assert sizeof(MPIPtr) == sizeof(Ptr{Cvoid}) -Base.cconvert(::Type{MPIPtr}, x::SentinelPtr) = x -Base.unsafe_convert(::Type{MPIPtr}, x::SentinelPtr) = reinterpret(MPIPtr, x) - function _doc_external(fname) """ @@ -33,30 +24,24 @@ function _doc_external(fname) """ end +""" + MPIError -import MPIPreferences - -if MPIPreferences.binary == "MPICH_jll" - import MPICH_jll: libmpi, libmpi_handle, mpiexec - const libmpiconstants = nothing -elseif MPIPreferences.binary == "OpenMPI_jll" - import OpenMPI_jll: libmpi, libmpi_handle, mpiexec - const libmpiconstants = nothing -elseif MPIPreferences.binary == "MicrosoftMPI_jll" - import MicrosoftMPI_jll: libmpi, libmpi_handle, mpiexec - const libmpiconstants = nothing -elseif MPIPreferences.binary == "MPItrampoline_jll" - import MPItrampoline_jll: MPItrampoline_jll, libmpi, libmpi_handle, mpiexec - const libmpiconstants = MPItrampoline_jll.libload_time_mpi_constants_path -elseif MPIPreferences.binary == "system" - import MPIPreferences.System: libmpi, libmpi_handle, mpiexec - const libmpiconstants = nothing -else - error("Unknown MPI binary: $(MPIPreferences.binary)") +Error thrown when an MPI function returns an error code. The `code` field contains the MPI error code. +""" +struct MPIError <: Exception + code::Cint end +function Base.show(io::IO, err::MPIError) + print(io, "MPIError(", err.code, "): ", error_string(err)) +end + -include("consts/consts.jl") -using .Consts + + +include("api/api.jl") +using .API +const Consts = API # These functions are run after reading the values of the constants above) const _mpi_load_time_hooks = Any[] @@ -73,21 +58,9 @@ function run_load_time_hooks() nothing end +using MPIPreferences include("implementations.jl") include("error.jl") - -module API - import ..libmpi, ..libmpi_handle, ..MPIPtr - import ..use_stdcall, ..MPIError, ..@mpicall, ..@mpichk - using ..Consts - - for name in filter(n -> startswith(string(n), "MPI_"), names(Consts; all = true)) - @eval $name = Consts.$name # signatures need types - end - - include("auto_generated_api.jl") -end - include("info.jl") include("group.jl") include("comm.jl") @@ -140,7 +113,7 @@ function __init__() # Needs to be called after `dlopen`. Use `invokelatest` so that `cglobal` # calls don't trigger early `dlopen`-ing of the library. - Base.invokelatest(Consts.init_consts) + Base.invokelatest(API.init_consts) # disable UCX memory cache, since it doesn't work correctly # https://github.com/openucx/ucx/issues/5061 @@ -157,7 +130,7 @@ function __init__() end if MPIPreferences.binary == "MPItrampoline_jll" && !haskey(ENV, "MPITRAMPOLINE_MPIEXEC") - ENV["MPITRAMPOLINE_MPIEXEC"] = MPItrampoline_jll.mpich_mpiexec_path + ENV["MPITRAMPOLINE_MPIEXEC"] = API.MPItrampoline_jll.mpich_mpiexec_path end run_load_time_hooks() diff --git a/src/api/api.jl b/src/api/api.jl new file mode 100644 index 000000000..912ab406f --- /dev/null +++ b/src/api/api.jl @@ -0,0 +1,138 @@ +module API + +export MPI_Aint, MPI_Count, MPI_Offset, MPI_Status, + MPI_Comm, MPI_Datatype, MPI_Errhandler, MPI_File, MPI_Group, + MPI_Info, MPI_Message, MPI_Op, MPI_Request, MPI_Win, + libmpi, mpiexec, @mpichk, @mpicall, MPIPtr, SentinelPtr, FeatureLevelError + +import MPIPreferences +using Libdl + +if MPIPreferences.binary == "MPICH_jll" + import MPICH_jll: libmpi, libmpi_handle, mpiexec + const libmpiconstants = nothing +elseif MPIPreferences.binary == "OpenMPI_jll" + import OpenMPI_jll: libmpi, libmpi_handle, mpiexec + const libmpiconstants = nothing +elseif MPIPreferences.binary == "MicrosoftMPI_jll" + import MicrosoftMPI_jll: libmpi, libmpi_handle, mpiexec + const libmpiconstants = nothing +elseif MPIPreferences.binary == "MPItrampoline_jll" + import MPItrampoline_jll: MPItrampoline_jll, libmpi, libmpi_handle, mpiexec + const libmpiconstants = MPItrampoline_jll.libload_time_mpi_constants_path +elseif MPIPreferences.binary == "system" + import MPIPreferences.System: libmpi, libmpi_handle, mpiexec + const libmpiconstants = nothing +else + error("Unknown MPI binary: $(MPIPreferences.binary)") +end + +import ..MPIError +const initexprs = Any[] + +""" + @const_ref name T expr + +Defines an constant binding +```julia +const name = Ref{T}() +``` +and adds a hook to execute +```julia +name[] = expr +``` +at module initialization time. +""" +macro const_ref(name, T, expr) + push!(initexprs, :($name[] = $expr)) + :(const $(esc(name)) = Ref{$T}()) +end + +@static if MPIPreferences.abi == "MPICH" + include("mpich.jl") +elseif MPIPreferences.abi == "OpenMPI" + include("openmpi.jl") +elseif MPIPreferences.abi == "MicrosoftMPI" + include("microsoftmpi.jl") +elseif MPIPreferences.abi == "MPItrampoline" + include("mpitrampoline.jl") +elseif MPIPreferences.abi == "HPE MPT" + include("mpt.jl") +else + error("Unknown MPI ABI $(MPIPreferences.abi)") +end + +primitive type SentinelPtr Sys.WORD_SIZE +end + +primitive type MPIPtr Sys.WORD_SIZE +end +@assert sizeof(MPIPtr) == sizeof(Ptr{Cvoid}) +Base.cconvert(::Type{MPIPtr}, x::SentinelPtr) = x +Base.unsafe_convert(::Type{MPIPtr}, x::SentinelPtr) = reinterpret(MPIPtr, x) + + +# Initialize the ref constants from the library. +# This is not `API.__init__`, as it should be called _after_ +# `dlopen` to ensure the library is opened correctly. +@eval function init_consts() + $(Expr(:block, initexprs...)) +end + +const use_stdcall = startswith(basename(libmpi), "msmpi") + +macro mpicall(expr) + @assert expr isa Expr && expr.head == :call && expr.args[1] == :ccall + + # On unix systems we call the global symbols to allow for LD_PRELOAD interception + # It can be emulated in Windows (via Libdl.dllist), but this is not fast. + if Sys.isunix() && expr.args[2].head == :tuple && + (VERSION ≥ v"1.5-" || expr.args[2].args[1] ≠ :(:MPI_Get_library_version)) + expr.args[2] = expr.args[2].args[1] + end + + # Microsoft MPI uses stdcall calling convention + # this only affects 32-bit Windows + # unfortunately we need to use ccall to call Get_library_version + # so check using library name instead + if use_stdcall + insert!(expr.args, 3, :stdcall) + end + return esc(expr) +end + +""" + FeatureLevelError + +Error thrown if a feature is not implemented in the current MPI backend. +""" +struct FeatureLevelError <: Exception + function_name::Symbol + min_version::VersionNumber # minimal MPI version required for this feature to be available +end +function Base.show(io::IO, err::FeatureLevelError) + print(io, "FeatureLevelError($(err.function_name)): Minimum MPI version is $(err.min_version)") +end + +macro mpichk(expr, min_version=nothing) + if !isnothing(min_version) && expr.args[2].head == :tuple + fn = expr.args[2].args[1].value + if isnothing(dlsym(libmpi_handle, fn; throw_error=false)) + return quote + throw(FeatureLevelError($(QuoteNode(fn)), $min_version)) + end + end + end + + expr = macroexpand(@__MODULE__, :(@mpicall($expr))) + # MPI_SUCCESS is defined to be 0 + :((errcode = $(esc(expr))) == 0 || throw(MPIError(errcode))) +end + + +include("generated_api.jl") + +# since this is called by invokelatest, it isn't automatically precompiled +precompile(init_consts, ()) + +end diff --git a/src/auto_generated_api.jl b/src/api/generated_api.jl similarity index 100% rename from src/auto_generated_api.jl rename to src/api/generated_api.jl diff --git a/src/consts/microsoftmpi.jl b/src/api/microsoftmpi.jl similarity index 100% rename from src/consts/microsoftmpi.jl rename to src/api/microsoftmpi.jl diff --git a/src/consts/mpich.jl b/src/api/mpich.jl similarity index 100% rename from src/consts/mpich.jl rename to src/api/mpich.jl diff --git a/src/consts/mpitrampoline.jl b/src/api/mpitrampoline.jl similarity index 100% rename from src/consts/mpitrampoline.jl rename to src/api/mpitrampoline.jl diff --git a/src/consts/mpt.jl b/src/api/mpt.jl similarity index 100% rename from src/consts/mpt.jl rename to src/api/mpt.jl diff --git a/src/consts/openmpi.jl b/src/api/openmpi.jl similarity index 100% rename from src/consts/openmpi.jl rename to src/api/openmpi.jl diff --git a/src/buffers.jl b/src/buffers.jl index d9b48eb66..d600b0345 100644 --- a/src/buffers.jl +++ b/src/buffers.jl @@ -54,7 +54,7 @@ MPIPtr struct InPlace end -Base.cconvert(::Type{MPIPtr}, ::InPlace) = Consts.MPI_IN_PLACE[] +Base.cconvert(::Type{MPIPtr}, ::InPlace) = API.MPI_IN_PLACE[] """ diff --git a/src/collective.jl b/src/collective.jl index b59902bbc..20dce82f7 100644 --- a/src/collective.jl +++ b/src/collective.jl @@ -464,7 +464,7 @@ If only one buffer `sendrecvbuf` is used, then data is overwritten. $(_doc_external("MPI_Alltoall")) """ function Alltoall!(sendbuf::UBuffer, recvbuf::UBuffer, comm::Comm) - if sendbuf.data !== Consts.MPI_IN_PLACE[] && sendbuf.nchunks !== nothing + if sendbuf.data !== API.MPI_IN_PLACE[] && sendbuf.nchunks !== nothing @assert sendbuf.nchunks >= Comm_size(comm) end if recvbuf.nchunks !== nothing @@ -521,7 +521,7 @@ Similar to [`Alltoall!`](@ref), except with different size chunks per process. $(_doc_external("MPI_Alltoallv")) """ function Alltoallv!(sendbuf::VBuffer, recvbuf::VBuffer, comm::Comm) - if sendbuf.data !== Consts.MPI_IN_PLACE[] + if sendbuf.data !== API.MPI_IN_PLACE[] @assert length(sendbuf.counts) >= Comm_size(comm) end @assert length(recvbuf.counts) >= Comm_size(comm) diff --git a/src/comm.jl b/src/comm.jl index 53fff966b..02b460a7a 100644 --- a/src/comm.jl +++ b/src/comm.jl @@ -12,8 +12,8 @@ Base.unsafe_convert(::Type{MPI_Comm}, comm::Comm) = comm.val Base.unsafe_convert(::Type{Ptr{MPI_Comm}}, comm::Comm) = convert(Ptr{MPI_Comm}, pointer_from_objref(comm)) -const COMM_NULL = Comm(Consts.MPI_COMM_NULL[]) -add_load_time_hook!(() -> COMM_NULL.val = Consts.MPI_COMM_NULL[]) +const COMM_NULL = Comm(API.MPI_COMM_NULL[]) +add_load_time_hook!(() -> COMM_NULL.val = API.MPI_COMM_NULL[]) """ MPI.COMM_WORLD @@ -21,16 +21,16 @@ add_load_time_hook!(() -> COMM_NULL.val = Consts.MPI_COMM_NULL[]) A communicator containing all processes with which the local rank can communicate at initialization. In a typical "static-process" model, this will be all processes. """ -const COMM_WORLD = Comm(Consts.MPI_COMM_WORLD[]) -add_load_time_hook!(() -> COMM_WORLD.val = Consts.MPI_COMM_WORLD[]) +const COMM_WORLD = Comm(API.MPI_COMM_WORLD[]) +add_load_time_hook!(() -> COMM_WORLD.val = API.MPI_COMM_WORLD[]) """ MPI.COMM_SELF A communicator containing only the local process. """ -const COMM_SELF = Comm(Consts.MPI_COMM_SELF[]) -add_load_time_hook!(() -> COMM_SELF.val = Consts.MPI_COMM_SELF[]) +const COMM_SELF = Comm(API.MPI_COMM_SELF[]) +add_load_time_hook!(() -> COMM_SELF.val = API.MPI_COMM_SELF[]) Comm() = Comm(COMM_NULL.val) @@ -173,7 +173,7 @@ $(_doc_external("MPI_Comm_split")) """ function Comm_split(comm::Comm, color::Union{Integer, Nothing}, key::Integer) if isnothing(color) - color = Consts.MPI_UNDEFINED[] + color = API.MPI_UNDEFINED[] end newcomm = Comm() API.MPI_Comm_split(comm, color, key, newcomm) @@ -185,7 +185,7 @@ mutable struct SplitType val::Cint end const COMM_TYPE_SHARED = SplitType(-1) -add_load_time_hook!(() -> COMM_TYPE_SHARED.val = Consts.MPI_COMM_TYPE_SHARED[]) +add_load_time_hook!(() -> COMM_TYPE_SHARED.val = API.MPI_COMM_TYPE_SHARED[]) """ @@ -205,7 +205,7 @@ $(_doc_external("MPI_Comm_split_type")) """ function Comm_split_type(comm::Comm, split_type, key::Integer; kwargs...) if isnothing(split_type) - split_type = Consts.MPI_UNDEFINED[] + split_type = API.MPI_UNDEFINED[] elseif split_type isa SplitType split_type = split_type.val end @@ -276,7 +276,7 @@ The total number of available slots, or `nothing` if it is not defined. This is This is typically dependent on the MPI implementation: for MPICH-based implementations, this is specified by the `-usize` argument. OpenMPI defines a default value based on the number of processes available. """ function universe_size() - ptr = unsafe_get_attr(COMM_WORLD, Consts.MPI_UNIVERSE_SIZE[]) + ptr = unsafe_get_attr(COMM_WORLD, API.MPI_UNIVERSE_SIZE[]) isnothing(ptr) && return nothing return Int(unsafe_load(Ptr{Cint}(ptr))) end @@ -287,7 +287,7 @@ end The maximum value tag value for point-to-point operations. """ function tag_ub() - ptr = something(unsafe_get_attr(COMM_WORLD, Consts.MPI_TAG_UB[])) + ptr = something(unsafe_get_attr(COMM_WORLD, API.MPI_TAG_UB[])) return Int(unsafe_load(Ptr{Cint}(ptr))) end diff --git a/src/consts/consts.jl b/src/consts/consts.jl deleted file mode 100644 index e1a98b2b3..000000000 --- a/src/consts/consts.jl +++ /dev/null @@ -1,54 +0,0 @@ -module Consts - -export MPI_Aint, MPI_Count, MPI_Offset, MPI_Status, - MPI_Comm, MPI_Datatype, MPI_Errhandler, MPI_File, MPI_Group, - MPI_Info, MPI_Message, MPI_Op, MPI_Request, MPI_Win - -import MPIPreferences -import ..libmpi, ..libmpiconstants - -const initexprs = Any[] - -""" - @const_ref name T expr - -Defines an constant binding -```julia -const name = Ref{T}() -``` -and adds a hook to execute -```julia -name[] = expr -``` -at module initialization time. -""" -macro const_ref(name, T, expr) - push!(initexprs, :($name[] = $expr)) - :(const $(esc(name)) = Ref{$T}()) -end - -@static if MPIPreferences.abi == "MPICH" - include("mpich.jl") -elseif MPIPreferences.abi == "OpenMPI" - include("openmpi.jl") -elseif MPIPreferences.abi == "MicrosoftMPI" - include("microsoftmpi.jl") -elseif MPIPreferences.abi == "MPItrampoline" - include("mpitrampoline.jl") -elseif MPIPreferences.abi == "HPE MPT" - include("mpt.jl") -else - error("Unknown MPI ABI $(MPIPreferences.abi)") -end - -# Initialize the ref constants from the library. -# This is not `Consts.__init__`, as it should be called _after_ -# `dlopen` to ensure the library is opened correctly. -@eval function init_consts() - $(Expr(:block, initexprs...)) -end - -# since this is called by invokelatest, it isn't automatically precompiled -precompile(init_consts, ()) - -end diff --git a/src/datatypes.jl b/src/datatypes.jl index dadbd72db..ce18afd62 100644 --- a/src/datatypes.jl +++ b/src/datatypes.jl @@ -21,8 +21,8 @@ Base.cconvert(::Type{MPI_Datatype}, datatype::Datatype) = datatype Base.unsafe_convert(::Type{MPI_Datatype}, datatype::Datatype) = datatype.val Base.unsafe_convert(::Type{Ptr{MPI_Datatype}}, datatype::Datatype) = convert(Ptr{MPI_Datatype}, pointer_from_objref(datatype)) -const DATATYPE_NULL = Datatype(Consts.MPI_DATATYPE_NULL[]) -add_load_time_hook!(() -> DATATYPE_NULL.val = Consts.MPI_DATATYPE_NULL[]) +const DATATYPE_NULL = Datatype(API.MPI_DATATYPE_NULL[]) +add_load_time_hook!(() -> DATATYPE_NULL.val = API.MPI_DATATYPE_NULL[]) Datatype() = Datatype(DATATYPE_NULL.val) @@ -37,7 +37,7 @@ end # attributes function create_keyval(::Type{Datatype}) ref = Ref(Cint(0)) - API.MPI_Type_create_keyval(Consts.MPI_TYPE_NULL_COPY_FN[], Consts.MPI_TYPE_NULL_DELETE_FN[], ref, C_NULL) + API.MPI_Type_create_keyval(API.MPI_TYPE_NULL_COPY_FN[], API.MPI_TYPE_NULL_DELETE_FN[], ref, C_NULL) return ref[] end function set_attr!(datatype::Datatype, keyval::Cint, attrval::Ptr{Cvoid}) @@ -58,7 +58,7 @@ end # names function get_name(datatype::Datatype) - buffer = Array{UInt8}(undef, Consts.MPI_MAX_OBJECT_NAME) + buffer = Array{UInt8}(undef, API.MPI_MAX_OBJECT_NAME) lenref = Ref{Cint}() API.MPI_Type_get_name(datatype, buffer, lenref) return String(resize!(buffer, lenref[])) @@ -115,8 +115,8 @@ for (mpiname, T) in [ ] @eval begin - const $mpiname = Datatype(Consts.$(Symbol(:MPI_,mpiname))[]) - add_load_time_hook!(() -> $mpiname.val = Consts.$(Symbol(:MPI_,mpiname))[]) + const $mpiname = Datatype(API.$(Symbol(:MPI_,mpiname))[]) + add_load_time_hook!(() -> $mpiname.val = API.$(Symbol(:MPI_,mpiname))[]) if $T ∉ _defined_datatype_methods push!(_defined_datatype_methods, $T) Datatype(::Type{$T}) = $mpiname @@ -289,7 +289,7 @@ function create_subarray!(newtype::Datatype, sizes, subsizes, offset, oldtype::D # MPI_Datatype oldtype, # MPI_Datatype *newtype) API.MPI_Type_create_subarray(N, sizes, subsizes, offset, - rowmajor ? MPI.Consts.MPI_ORDER_C[] : MPI.Consts.MPI_ORDER_FORTRAN[], + rowmajor ? MPI.API.MPI_ORDER_C[] : MPI.API.MPI_ORDER_FORTRAN[], oldtype, newtype) return newtype end diff --git a/src/environment.jl b/src/environment.jl index cee7bb0d9..e9e585df2 100644 --- a/src/environment.jl +++ b/src/environment.jl @@ -140,14 +140,14 @@ An Enum denoting the level of threading support in the current process: mutable struct ThreadLevel val::Cint end -const THREAD_SINGLE = ThreadLevel(Consts.MPI_THREAD_SINGLE[]) -const THREAD_FUNNELED = ThreadLevel(Consts.MPI_THREAD_FUNNELED[]) -const THREAD_SERIALIZED = ThreadLevel(Consts.MPI_THREAD_SERIALIZED[]) -const THREAD_MULTIPLE = ThreadLevel(Consts.MPI_THREAD_MULTIPLE[]) -add_load_time_hook!(() -> THREAD_SINGLE.val = Consts.MPI_THREAD_SINGLE[] ) -add_load_time_hook!(() -> THREAD_FUNNELED.val = Consts.MPI_THREAD_FUNNELED[] ) -add_load_time_hook!(() -> THREAD_SERIALIZED.val = Consts.MPI_THREAD_SERIALIZED[]) -add_load_time_hook!(() -> THREAD_MULTIPLE.val = Consts.MPI_THREAD_MULTIPLE[] ) +const THREAD_SINGLE = ThreadLevel(API.MPI_THREAD_SINGLE[]) +const THREAD_FUNNELED = ThreadLevel(API.MPI_THREAD_FUNNELED[]) +const THREAD_SERIALIZED = ThreadLevel(API.MPI_THREAD_SERIALIZED[]) +const THREAD_MULTIPLE = ThreadLevel(API.MPI_THREAD_MULTIPLE[]) +add_load_time_hook!(() -> THREAD_SINGLE.val = API.MPI_THREAD_SINGLE[] ) +add_load_time_hook!(() -> THREAD_FUNNELED.val = API.MPI_THREAD_FUNNELED[] ) +add_load_time_hook!(() -> THREAD_SERIALIZED.val = API.MPI_THREAD_SERIALIZED[]) +add_load_time_hook!(() -> THREAD_MULTIPLE.val = API.MPI_THREAD_MULTIPLE[] ) ThreadLevel(threadlevel::Symbol) = threadlevel == :single ? THREAD_SINGLE : threadlevel == :funneled ? THREAD_FUNNELED : diff --git a/src/errhandler.jl b/src/errhandler.jl index 92dd0678d..cefac0439 100644 --- a/src/errhandler.jl +++ b/src/errhandler.jl @@ -14,12 +14,12 @@ Base.cconvert(::Type{MPI_Errhandler}, errhandler::Errhandler) = errhandler Base.unsafe_convert(::Type{MPI_Errhandler}, errhandler::Errhandler) = errhandler.val Base.unsafe_convert(::Type{Ptr{MPI_Errhandler}}, errhandler::Errhandler) = convert(Ptr{MPI_Errhandler}, pointer_from_objref(errhandler)) -const ERRHANDLER_NULL = Errhandler(Consts.MPI_ERRHANDLER_NULL[]) -const ERRORS_ARE_FATAL = Errhandler(Consts.MPI_ERRORS_ARE_FATAL[]) -const ERRORS_RETURN = Errhandler(Consts.MPI_ERRORS_RETURN[] ) -add_load_time_hook!(() -> ERRHANDLER_NULL.val = Consts.MPI_ERRHANDLER_NULL[] ) -add_load_time_hook!(() -> ERRORS_ARE_FATAL.val = Consts.MPI_ERRORS_ARE_FATAL[]) -add_load_time_hook!(() -> ERRORS_RETURN.val = Consts.MPI_ERRORS_RETURN[] ) +const ERRHANDLER_NULL = Errhandler(API.MPI_ERRHANDLER_NULL[]) +const ERRORS_ARE_FATAL = Errhandler(API.MPI_ERRORS_ARE_FATAL[]) +const ERRORS_RETURN = Errhandler(API.MPI_ERRORS_RETURN[] ) +add_load_time_hook!(() -> ERRHANDLER_NULL.val = API.MPI_ERRHANDLER_NULL[] ) +add_load_time_hook!(() -> ERRORS_ARE_FATAL.val = API.MPI_ERRORS_ARE_FATAL[]) +add_load_time_hook!(() -> ERRORS_RETURN.val = API.MPI_ERRORS_RETURN[] ) Errhandler() = Errhandler(ERRHANDLER_NULL.val) diff --git a/src/error.jl b/src/error.jl index 80f382dc9..886fb8170 100644 --- a/src/error.jl +++ b/src/error.jl @@ -1,49 +1,9 @@ -""" - MPIError - -Error thrown when an MPI function returns an error code. The `code` field contains the MPI error code. -""" -struct MPIError <: Exception - code::Cint -end -function Base.show(io::IO, err::MPIError) - print(io, "MPIError(", err.code, "): ", error_string(err)) -end - -""" - FeatureLevelError - -Error thrown if a feature is not implemented in the current MPI backend. -""" -struct FeatureLevelError <: Exception - function_name::Symbol - min_version::VersionNumber # minimal MPI version required for this feature to be available -end -function Base.show(io::IO, err::FeatureLevelError) - print(io, "FeatureLevelError($(err.function_name)): Minimum MPI version is $(err.min_version)") -end - -macro mpichk(expr, min_version=nothing) - if !isnothing(min_version) && expr.args[2].head == :tuple - fn = expr.args[2].args[1].value - if isnothing(dlsym(libmpi_handle, fn; throw_error=false)) - return quote - throw(FeatureLevelError($(QuoteNode(fn)), $min_version)) - end - end - end - - expr = macroexpand(@__MODULE__, :(@mpicall($expr))) - # MPI_SUCCESS is defined to be 0 - :((errcode = $(esc(expr))) == 0 || throw(MPIError(errcode))) -end function error_string(err::MPIError) len_ref = Ref{Cint}() - str_buf = Vector{UInt8}(undef, Consts.MPI_MAX_ERROR_STRING) + str_buf = Vector{UInt8}(undef, API.MPI_MAX_ERROR_STRING) # int MPI_Error_string(int errorcode, char *string, int *resultlen) - @mpichk ccall((:MPI_Error_string, libmpi), Cint, - (Cint, Ptr{UInt8}, Ref{Cint}), err.code, str_buf, len_ref) + API.MPI_Error_string(err.code, str_buf, len_ref) resize!(str_buf, len_ref[]) return String(str_buf) end diff --git a/src/group.jl b/src/group.jl index 3518d5422..09730a7cc 100644 --- a/src/group.jl +++ b/src/group.jl @@ -11,10 +11,10 @@ Base.cconvert(::Type{MPI_Group}, group::Group) = group Base.unsafe_convert(::Type{MPI_Group}, group::Group) = group.val Base.unsafe_convert(::Type{Ptr{MPI_Group}}, group::Group) = convert(Ptr{MPI_Group}, pointer_from_objref(group)) -const GROUP_NULL = Group(Consts.MPI_GROUP_NULL[]) -const GROUP_EMPTY = Group(Consts.MPI_GROUP_EMPTY[]) -add_load_time_hook!(() -> GROUP_NULL.val = Consts.MPI_GROUP_NULL[]) -add_load_time_hook!(() -> GROUP_EMPTY.val = Consts.MPI_GROUP_EMPTY[]) +const GROUP_NULL = Group(API.MPI_GROUP_NULL[]) +const GROUP_EMPTY = Group(API.MPI_GROUP_EMPTY[]) +add_load_time_hook!(() -> GROUP_NULL.val = API.MPI_GROUP_NULL[]) +add_load_time_hook!(() -> GROUP_EMPTY.val = API.MPI_GROUP_EMPTY[]) Group() = Group(GROUP_NULL.val) @@ -76,14 +76,14 @@ An enum denoting the result of [`Comm_compare`](@ref): mutable struct Comparison val::Cint end -const IDENT = Comparison(Consts.MPI_IDENT[]) -const CONGRUENT = Comparison(Consts.MPI_CONGRUENT[]) -const SIMILAR = Comparison(Consts.MPI_SIMILAR[]) -const UNEQUAL = Comparison(Consts.MPI_UNEQUAL[]) -add_load_time_hook!(() -> IDENT.val = Consts.MPI_IDENT[] ) -add_load_time_hook!(() -> CONGRUENT.val = Consts.MPI_CONGRUENT[]) -add_load_time_hook!(() -> SIMILAR.val = Consts.MPI_SIMILAR[] ) -add_load_time_hook!(() -> UNEQUAL.val = Consts.MPI_UNEQUAL[] ) +const IDENT = Comparison(API.MPI_IDENT[]) +const CONGRUENT = Comparison(API.MPI_CONGRUENT[]) +const SIMILAR = Comparison(API.MPI_SIMILAR[]) +const UNEQUAL = Comparison(API.MPI_UNEQUAL[]) +add_load_time_hook!(() -> IDENT.val = API.MPI_IDENT[] ) +add_load_time_hook!(() -> CONGRUENT.val = API.MPI_CONGRUENT[]) +add_load_time_hook!(() -> SIMILAR.val = API.MPI_SIMILAR[] ) +add_load_time_hook!(() -> UNEQUAL.val = API.MPI_UNEQUAL[] ) Base.:(==)(tl1::Comparison, tl2::Comparison) = tl1.val == tl2.val function Group_compare(group1::Group, group2::Group) diff --git a/src/implementations.jl b/src/implementations.jl index bf385a267..cde23e319 100644 --- a/src/implementations.jl +++ b/src/implementations.jl @@ -1,29 +1,9 @@ -const use_stdcall = startswith(basename(libmpi), "msmpi") # This is required in addition to __init__() so that we can call library at precompilation time. if Sys.isunix() Libdl.dlopen(libmpi, Libdl.RTLD_LAZY | Libdl.RTLD_GLOBAL) end -macro mpicall(expr) - @assert expr isa Expr && expr.head == :call && expr.args[1] == :ccall - - # On unix systems we call the global symbols to allow for LD_PRELOAD interception - # It can be emulated in Windows (via Libdl.dllist), but this is not fast. - if Sys.isunix() && expr.args[2].head == :tuple && - (VERSION ≥ v"1.5-" || expr.args[2].args[1] ≠ :(:MPI_Get_library_version)) - expr.args[2] = expr.args[2].args[1] - end - - # Microsoft MPI uses stdcall calling convention - # this only affects 32-bit Windows - # unfortunately we need to use ccall to call Get_library_version - # so check using library name instead - if use_stdcall - insert!(expr.args, 3, :stdcall) - end - return esc(expr) -end function Get_library_version() # There is no way to query at runtime what the length of the buffer should be. @@ -33,7 +13,7 @@ function Get_library_version() buf = Array{UInt8}(undef, 8192) buflen = Ref{Cint}() - @mpicall ccall((:MPI_Get_library_version, libmpi), Cint, (Ptr{UInt8}, Ref{Cint}), buf, buflen) + API.MPI_Get_library_version(buf, buflen) @assert buflen[] < 8192 resize!(buf, buflen[]) return String(buf) @@ -86,8 +66,7 @@ MPI_LIBRARY_VERSION function Get_version() major = Ref{Cint}() minor = Ref{Cint}() - @mpicall ccall((:MPI_Get_version, libmpi), Cint, - (Ptr{Cint}, Ptr{Cint}), major, minor) + API.MPI_Get_version(major, minor) VersionNumber(major[], minor[]) end diff --git a/src/info.jl b/src/info.jl index 7eb42cb53..595dd17b9 100644 --- a/src/info.jl +++ b/src/info.jl @@ -33,8 +33,8 @@ Base.cconvert(::Type{MPI_Info}, info::Info) = info Base.unsafe_convert(::Type{MPI_Info}, info::Info) = info.val Base.unsafe_convert(::Type{Ptr{MPI_Info}}, info::Info) = convert(Ptr{MPI_Info}, pointer_from_objref(info)) -const INFO_NULL = Info(Consts.MPI_INFO_NULL[]) -add_load_time_hook!(() -> INFO_NULL.val = Consts.MPI_INFO_NULL[]) +const INFO_NULL = Info(API.MPI_INFO_NULL[]) +add_load_time_hook!(() -> INFO_NULL.val = API.MPI_INFO_NULL[]) function Info(;init=false) info = Info(INFO_NULL.val) @@ -56,7 +56,7 @@ end function Base.setindex!(info::Info, value::AbstractString, key::Symbol) skey = String(key) @assert isascii(skey) && isascii(value) && - length(skey) <= Consts.MPI_MAX_INFO_KEY && length(value) <= Consts.MPI_MAX_INFO_VAL + length(skey) <= API.MPI_MAX_INFO_KEY && length(value) <= API.MPI_MAX_INFO_VAL API.MPI_Info_set(info, skey, value) end @@ -86,7 +86,7 @@ end function Base.getindex(info::Info, key::Symbol) skey = String(key) - @assert isascii(skey) && length(skey) <= Consts.MPI_MAX_INFO_KEY + @assert isascii(skey) && length(skey) <= API.MPI_MAX_INFO_KEY valuelen = Ref{Cint}() flag = Ref{Cint}() # int MPI_Info_get_valuelen(MPI_Info info, const char *key, int *valuelen, int *flag) @@ -109,7 +109,7 @@ end function Base.delete!(info::Info,key::Symbol) skey = String(key) - @assert isascii(skey) && length(skey) <= Consts.MPI_MAX_INFO_KEY + @assert isascii(skey) && length(skey) <= API.MPI_MAX_INFO_KEY API.MPI_Info_delete(info, skey) end @@ -123,7 +123,7 @@ function Base.length(info::Info) end function nthkey(info::Info, n::Integer) - buffer = Vector{UInt8}(undef, Consts.MPI_MAX_INFO_KEY+1) + buffer = Vector{UInt8}(undef, API.MPI_MAX_INFO_KEY+1) API.MPI_Info_get_nthkey(info, n, buffer) i = findfirst(isequal(UInt8(0)), buffer) if i !== nothing diff --git a/src/io.jl b/src/io.jl index 42a410ffb..eee6248d9 100644 --- a/src/io.jl +++ b/src/io.jl @@ -6,8 +6,8 @@ Base.cconvert(::Type{MPI_File}, file::FileHandle) = file Base.unsafe_convert(::Type{MPI_File}, file::FileHandle) = file.val Base.unsafe_convert(::Type{Ptr{MPI_File}}, file::FileHandle) = convert(Ptr{MPI_File}, pointer_from_objref(file)) -const FILE_NULL = FileHandle(Consts.MPI_FILE_NULL[]) -add_load_time_hook!(() -> FILE_NULL.val = Consts.MPI_FILE_NULL[]) +const FILE_NULL = FileHandle(API.MPI_FILE_NULL[]) +add_load_time_hook!(() -> FILE_NULL.val = API.MPI_FILE_NULL[]) FileHandle() = FileHandle(FILE_NULL.val) @@ -48,15 +48,15 @@ function open(comm::Comm, filename::AbstractString; infokws...) flags = Base.open_flags(read=read, write=write, create=create, truncate=nothing, append=append) amode = if flags.read - flags.write ? MPI.Consts.MPI_MODE_RDWR[] : MPI.Consts.MPI_MODE_RDONLY[] + flags.write ? MPI.API.MPI_MODE_RDWR[] : MPI.API.MPI_MODE_RDONLY[] else - flags.write ? MPI.Consts.MPI_MODE_WRONLY[] : zero(Cint) + flags.write ? MPI.API.MPI_MODE_WRONLY[] : zero(Cint) end - flags.write && (amode |= flags.create ? MPI.Consts.MPI_MODE_CREATE[] : MPI.Consts.MPI_MODE_EXCL[]) - flags.append && (amode |= MPI.Consts.MPI_MODE_APPEND[]) - sequential && (amode |= MPI.Consts.MPI_MODE_SEQUENTIAL[]) - uniqueopen && (amode |= MPI.Consts.MPI_MODE_UNIQUE_OPEN[]) - deleteonclose && (amode |= MPI.Consts.MPI_MODE_DELETE_ON_CLOSE[]) + flags.write && (amode |= flags.create ? MPI.API.MPI_MODE_CREATE[] : MPI.API.MPI_MODE_EXCL[]) + flags.append && (amode |= MPI.API.MPI_MODE_APPEND[]) + sequential && (amode |= MPI.API.MPI_MODE_SEQUENTIAL[]) + uniqueopen && (amode |= MPI.API.MPI_MODE_UNIQUE_OPEN[]) + deleteonclose && (amode |= MPI.API.MPI_MODE_DELETE_ON_CLOSE[]) open(comm, filename, amode, Info(infokws...)) end @@ -393,7 +393,7 @@ $(_doc_external("MPI_File_write_ordered")) function write_ordered(file::FileHandle, buf::Buffer) stat_ref = Ref(MPI.STATUS_ZERO) # int MPI_File_write_ordered(MPI_File fh, const void *buf, int count, - # MPI_Datatype datatype, MPI_Status *status) + # MPI_Datatype datatype, MPI_Status *status) API.MPI_File_write_ordered(file, buf.data, buf.count, buf.datatype, stat_ref) return stat_ref[] end @@ -403,12 +403,12 @@ write_ordered(file::FileHandle, buf) = write_ordered(file, Buffer_send(buf)) mutable struct Seek val::Cint end -const SEEK_SET = Seek(MPI.Consts.MPI_SEEK_SET[]) -const SEEK_CUR = Seek(MPI.Consts.MPI_SEEK_CUR[]) -const SEEK_END = Seek(MPI.Consts.MPI_SEEK_END[]) -MPI.add_load_time_hook!(() -> SEEK_SET.val = MPI.Consts.MPI_SEEK_SET[]) -MPI.add_load_time_hook!(() -> SEEK_CUR.val = MPI.Consts.MPI_SEEK_CUR[]) -MPI.add_load_time_hook!(() -> SEEK_END.val = MPI.Consts.MPI_SEEK_END[]) +const SEEK_SET = Seek(MPI.API.MPI_SEEK_SET[]) +const SEEK_CUR = Seek(MPI.API.MPI_SEEK_CUR[]) +const SEEK_END = Seek(MPI.API.MPI_SEEK_END[]) +MPI.add_load_time_hook!(() -> SEEK_SET.val = MPI.API.MPI_SEEK_SET[]) +MPI.add_load_time_hook!(() -> SEEK_CUR.val = MPI.API.MPI_SEEK_CUR[]) +MPI.add_load_time_hook!(() -> SEEK_END.val = MPI.API.MPI_SEEK_END[]) """ MPI.File.seek_shared(file::FileHandle, offset::Integer, whence::Seek=SEEK_SET) diff --git a/src/misc.jl b/src/misc.jl index ba9a37ce6..c45cb8566 100644 --- a/src/misc.jl +++ b/src/misc.jl @@ -7,9 +7,9 @@ Return the name of the processor, as a `String`. $(_doc_external("MPI_Get_processor_name")) """ function Get_processor_name() - proc_name = Array{UInt8}(undef, Consts.MPI_MAX_PROCESSOR_NAME) + proc_name = Array{UInt8}(undef, API.MPI_MAX_PROCESSOR_NAME) name_len = Ref{Cint}(0) API.MPI_Get_processor_name(proc_name, name_len) - @assert name_len[] <= Consts.MPI_MAX_PROCESSOR_NAME + @assert name_len[] <= API.MPI_MAX_PROCESSOR_NAME GC.@preserve proc_name unsafe_string(pointer(proc_name)) end diff --git a/src/nonblocking.jl b/src/nonblocking.jl index ad6d45bb4..4145d4519 100644 --- a/src/nonblocking.jl +++ b/src/nonblocking.jl @@ -62,8 +62,8 @@ Base.cconvert(::Type{MPI_Request}, request::Request) = request Base.unsafe_convert(::Type{MPI_Request}, request::Request) = request.val Base.unsafe_convert(::Type{Ptr{MPI_Request}}, request::Request) = convert(Ptr{MPI_Request}, pointer_from_objref(request)) -const REQUEST_NULL = Request(Consts.MPI_REQUEST_NULL[], nothing) -add_load_time_hook!(() -> REQUEST_NULL.val = Consts.MPI_REQUEST_NULL[]) +const REQUEST_NULL = Request(API.MPI_REQUEST_NULL[], nothing) +add_load_time_hook!(() -> REQUEST_NULL.val = API.MPI_REQUEST_NULL[]) Request() = Request(REQUEST_NULL.val, nothing) isnull(req::Request) = req == REQUEST_NULL @@ -141,7 +141,7 @@ $(_doc_external("MPI_Wait")) """ function Wait(req::Request, status::Union{Ref{Status}, Nothing}=nothing) # int MPI_Wait(MPI_Request *request, MPI_Status *status) - API.MPI_Wait(req, something(status, Consts.MPI_STATUS_IGNORE[])) + API.MPI_Wait(req, something(status, API.MPI_STATUS_IGNORE[])) # only clear the buffer for non-persistent requests isnull(req) && (req.buffer = nothing) return nothing @@ -166,7 +166,7 @@ $(_doc_external("MPI_Test")) function Test(req::Request, status::Union{Ref{Status}, Nothing}=nothing) flag = Ref{Cint}() # int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status) - API.MPI_Test(req, flag, something(status, Consts.MPI_STATUS_IGNORE[])) + API.MPI_Test(req, flag, something(status, API.MPI_STATUS_IGNORE[])) isnull(req) && (req.buffer = nothing) return flag[] != 0 end @@ -237,7 +237,7 @@ function Waitall(reqs::RequestSet, statuses::Union{AbstractVector{Status},Nothin @assert isnothing(statuses) || length(statuses) >= n # int MPI_Waitall(int count, MPI_Request array_of_requests[], # MPI_Status array_of_statuses[]) - API.MPI_Waitall(n, reqs.vals, something(statuses, Consts.MPI_STATUSES_IGNORE[])) + API.MPI_Waitall(n, reqs.vals, something(statuses, API.MPI_STATUSES_IGNORE[])) update!(reqs) return nothing end @@ -269,7 +269,7 @@ function Testall(reqs::RequestSet, statuses::Union{AbstractVector{Status},Nothin @assert isnothing(statuses) || length(statuses) >= n # int MPI_Testall(int count, MPI_Request array_of_requests[], int *flag, # MPI_Status array_of_statuses[]) - API.MPI_Testall(n, reqs.vals, flag, something(statuses, Consts.MPI_STATUSES_IGNORE[])) + API.MPI_Testall(n, reqs.vals, flag, something(statuses, API.MPI_STATUSES_IGNORE[])) update!(reqs) return flag[] != 0 end @@ -300,9 +300,9 @@ function Waitany(reqs::RequestSet, status::Union{Ref{Status}, Nothing}=nothing) n = length(reqs) # int MPI_Waitany(int count, MPI_Request array_of_requests[], int *index, # MPI_Status *status) - API.MPI_Waitany(n, reqs.vals, ref_idx, something(status, Consts.MPI_STATUS_IGNORE[])) + API.MPI_Waitany(n, reqs.vals, ref_idx, something(status, API.MPI_STATUS_IGNORE[])) idx = ref_idx[] - idx == Consts.MPI_UNDEFINED[] && return nothing + idx == API.MPI_UNDEFINED[] && return nothing i = Int(idx) + 1 update!(reqs, i) return i @@ -338,10 +338,10 @@ function Testany(reqs::RequestSet, status::Union{Ref{Status}, Nothing}=nothing) n = length(reqs) # int MPI_Testany(int count, MPI_Request array_of_requests[], int *index, # int *flag, MPI_Status *status) - API.MPI_Testany(n, reqs.vals, ref_idx, rflag, something(status, Consts.MPI_STATUS_IGNORE[])) + API.MPI_Testany(n, reqs.vals, ref_idx, rflag, something(status, API.MPI_STATUS_IGNORE[])) idx = ref_idx[] flag = rflag[] != 0 - idx == Consts.MPI_UNDEFINED[] && return flag, nothing + idx == API.MPI_UNDEFINED[] && return flag, nothing i = Int(idx) + 1 update!(reqs, i) return flag, i @@ -376,10 +376,10 @@ function Waitsome(reqs::RequestSet, statuses::Union{AbstractVector{Status},Nothi # int MPI_Waitsome(int incount, MPI_Request array_of_requests[], # int *outcount, int array_of_indices[], # MPI_Status array_of_statuses[]) - API.MPI_Waitsome(n, reqs.vals, ref_nout, idxs, something(statuses, Consts.MPI_STATUSES_IGNORE[])) + API.MPI_Waitsome(n, reqs.vals, ref_nout, idxs, something(statuses, API.MPI_STATUSES_IGNORE[])) nout = Int(ref_nout[]) # This can happen if there were no valid requests - nout == Consts.MPI_UNDEFINED[] && return nothing + nout == API.MPI_UNDEFINED[] && return nothing update!(reqs) return [Int(idxs[i]) + 1 for i = 1:nout] end @@ -414,10 +414,10 @@ function Testsome(reqs::RequestSet, statuses::Union{AbstractVector{Status},Nothi # int MPI_Testsome(int incount, MPI_Request array_of_requests[], # int *outcount, int array_of_indices[], # MPI_Status array_of_statuses[]) - API.MPI_Testsome(n, reqs.vals, ref_nout, idxs, something(statuses, Consts.MPI_STATUSES_IGNORE[])) + API.MPI_Testsome(n, reqs.vals, ref_nout, idxs, something(statuses, API.MPI_STATUSES_IGNORE[])) nout = Int(ref_nout[]) # This can happen if there were no valid requests - nout == Consts.MPI_UNDEFINED[] && return nothing + nout == API.MPI_UNDEFINED[] && return nothing update!(reqs) return [Int(idxs[i]) + 1 for i = 1:nout] end diff --git a/src/onesided.jl b/src/onesided.jl index 309ef92e6..9a0597f5c 100644 --- a/src/onesided.jl +++ b/src/onesided.jl @@ -7,8 +7,8 @@ Base.cconvert(::Type{MPI_Win}, win::Win) = win Base.unsafe_convert(::Type{MPI_Win}, win::Win) = win.val Base.unsafe_convert(::Type{Ptr{MPI_Win}}, win::Win) = convert(Ptr{MPI_Win}, pointer_from_objref(win)) -const WIN_NULL = Win(Consts.MPI_WIN_NULL[], nothing) -add_load_time_hook!(() -> WIN_NULL.val = Consts.MPI_WIN_NULL[]) +const WIN_NULL = Win(API.MPI_WIN_NULL[], nothing) +add_load_time_hook!(() -> WIN_NULL.val = API.MPI_WIN_NULL[]) Win() = Win(WIN_NULL.val, nothing) @@ -29,10 +29,10 @@ Base.cconvert(::Type{Cint}, lock_type::LockType) = lock_type Base.unsafe_convert(::Type{Cint}, lock_type::LockType) = lock_type.val Base.unsafe_convert(::Type{Ptr{Cint}}, lock_type::LockType) = convert(Ptr{Cint}, pointer_from_objref(lock_type)) -const LOCK_EXCLUSIVE = LockType(Consts.MPI_LOCK_EXCLUSIVE[]) -const LOCK_SHARED = LockType(Consts.MPI_LOCK_SHARED[] ) -add_load_time_hook!(() -> LOCK_EXCLUSIVE.val = Consts.MPI_LOCK_EXCLUSIVE[]) -add_load_time_hook!(() -> LOCK_SHARED.val = Consts.MPI_LOCK_SHARED[] ) +const LOCK_EXCLUSIVE = LockType(API.MPI_LOCK_EXCLUSIVE[]) +const LOCK_SHARED = LockType(API.MPI_LOCK_SHARED[] ) +add_load_time_hook!(() -> LOCK_EXCLUSIVE.val = API.MPI_LOCK_EXCLUSIVE[]) +add_load_time_hook!(() -> LOCK_SHARED.val = API.MPI_LOCK_SHARED[] ) LockType(sym::Symbol) = sym ≡ :exclusive ? LOCK_EXCLUSIVE : sym ≡ :shared ? LOCK_SHARED : @@ -171,10 +171,10 @@ Win_fence(assert::Integer, win::Win) = API.MPI_Win_fence(assert, win) function Win_fence(win::Win; nostore=false, noput=false, noprecede=false, nosucceed=false) assert = - (nostore * Consts.MPI_MODE_NOSTORE[]) | - (noput * Consts.MPI_MODE_NOPUT[]) | - (noprecede * Consts.MPI_MODE_NOPRECEDE[]) | - (nosucceed * Consts.MPI_MODE_NOSUCCEED[]) + (nostore * API.MPI_MODE_NOSTORE[]) | + (noput * API.MPI_MODE_NOPUT[]) | + (noprecede * API.MPI_MODE_NOPRECEDE[]) | + (nosucceed * API.MPI_MODE_NOSUCCEED[]) Win_fence(assert, win) end @@ -216,7 +216,7 @@ may be attached to the lock and unlock calls are still required. $(_doc_external("MPI_Win_lock")) """ function Win_lock(win::Win; rank::Integer, type::Union{Symbol,LockType}, nocheck::Bool = false) - Win_lock(type isa Symbol ? LockType(type) : type, rank, nocheck * Consts.MPI_MODE_NOCHECK[], win) + Win_lock(type isa Symbol ? LockType(type) : type, rank, nocheck * API.MPI_MODE_NOCHECK[], win) end function Win_lock(lock_type::LockType, rank::Integer, assert::Integer, win::Win) # int MPI_Win_lock(int lock_type, int rank, int assert, MPI_Win win) diff --git a/src/operators.jl b/src/operators.jl index ea1d32662..df32ef690 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -27,32 +27,32 @@ Base.cconvert(::Type{MPI_Op}, op::Op) = op Base.unsafe_convert(::Type{MPI_Op}, op::Op) = op.val Base.unsafe_convert(::Type{Ptr{MPI_Op}}, op::Op) = convert(Ptr{MPI_Op}, pointer_from_objref(op)) -const OP_NULL = Op(Consts.MPI_OP_NULL[], nothing) -const BAND = Op(Consts.MPI_BAND[], nothing) -const BOR = Op(Consts.MPI_BOR[], nothing) -const BXOR = Op(Consts.MPI_BXOR[], nothing) -const LAND = Op(Consts.MPI_LAND[], nothing) -const LOR = Op(Consts.MPI_LOR[], nothing) -const LXOR = Op(Consts.MPI_LXOR[], nothing) -const MAX = Op(Consts.MPI_MAX[], nothing) -const MIN = Op(Consts.MPI_MIN[], nothing) -const PROD = Op(Consts.MPI_PROD[], nothing) -const REPLACE = Op(Consts.MPI_REPLACE[], nothing) -const SUM = Op(Consts.MPI_SUM[], nothing) -const NO_OP = Op(Consts.MPI_NO_OP[], nothing) -add_load_time_hook!(() -> OP_NULL.val = Consts.MPI_OP_NULL[]) -add_load_time_hook!(() -> BAND.val = Consts.MPI_BAND[] ) -add_load_time_hook!(() -> BOR.val = Consts.MPI_BOR[] ) -add_load_time_hook!(() -> BXOR.val = Consts.MPI_BXOR[] ) -add_load_time_hook!(() -> LAND.val = Consts.MPI_LAND[] ) -add_load_time_hook!(() -> LOR.val = Consts.MPI_LOR[] ) -add_load_time_hook!(() -> LXOR.val = Consts.MPI_LXOR[] ) -add_load_time_hook!(() -> MAX.val = Consts.MPI_MAX[] ) -add_load_time_hook!(() -> MIN.val = Consts.MPI_MIN[] ) -add_load_time_hook!(() -> PROD.val = Consts.MPI_PROD[] ) -add_load_time_hook!(() -> REPLACE.val = Consts.MPI_REPLACE[]) -add_load_time_hook!(() -> SUM.val = Consts.MPI_SUM[] ) -add_load_time_hook!(() -> NO_OP.val = Consts.MPI_NO_OP[] ) +const OP_NULL = Op(API.MPI_OP_NULL[], nothing) +const BAND = Op(API.MPI_BAND[], nothing) +const BOR = Op(API.MPI_BOR[], nothing) +const BXOR = Op(API.MPI_BXOR[], nothing) +const LAND = Op(API.MPI_LAND[], nothing) +const LOR = Op(API.MPI_LOR[], nothing) +const LXOR = Op(API.MPI_LXOR[], nothing) +const MAX = Op(API.MPI_MAX[], nothing) +const MIN = Op(API.MPI_MIN[], nothing) +const PROD = Op(API.MPI_PROD[], nothing) +const REPLACE = Op(API.MPI_REPLACE[], nothing) +const SUM = Op(API.MPI_SUM[], nothing) +const NO_OP = Op(API.MPI_NO_OP[], nothing) +add_load_time_hook!(() -> OP_NULL.val = API.MPI_OP_NULL[]) +add_load_time_hook!(() -> BAND.val = API.MPI_BAND[] ) +add_load_time_hook!(() -> BOR.val = API.MPI_BOR[] ) +add_load_time_hook!(() -> BXOR.val = API.MPI_BXOR[] ) +add_load_time_hook!(() -> LAND.val = API.MPI_LAND[] ) +add_load_time_hook!(() -> LOR.val = API.MPI_LOR[] ) +add_load_time_hook!(() -> LXOR.val = API.MPI_LXOR[] ) +add_load_time_hook!(() -> MAX.val = API.MPI_MAX[] ) +add_load_time_hook!(() -> MIN.val = API.MPI_MIN[] ) +add_load_time_hook!(() -> PROD.val = API.MPI_PROD[] ) +add_load_time_hook!(() -> REPLACE.val = API.MPI_REPLACE[]) +add_load_time_hook!(() -> SUM.val = API.MPI_SUM[] ) +add_load_time_hook!(() -> NO_OP.val = API.MPI_NO_OP[] ) Op(::typeof(min), ::Type{T}; iscommutative=true) where {T<:Union{MPIInteger,MPIFloatingPoint}} = MIN Op(::typeof(max), ::Type{T}; iscommutative=true) where {T<:Union{MPIInteger,MPIFloatingPoint}} = MAX diff --git a/src/pointtopoint.jl b/src/pointtopoint.jl index 302cd3a96..634abac4e 100644 --- a/src/pointtopoint.jl +++ b/src/pointtopoint.jl @@ -106,13 +106,13 @@ Optionally returns the [`Status`](@ref) object of the receive. # External links $(_doc_external("MPI_Recv")) """ -Recv!(recvbuf, comm::Comm, status=nothing; source=Consts.MPI_ANY_SOURCE[], tag=Consts.MPI_ANY_TAG[]) = +Recv!(recvbuf, comm::Comm, status=nothing; source=API.MPI_ANY_SOURCE[], tag=API.MPI_ANY_TAG[]) = Recv!(recvbuf, source, tag, comm, status) function Recv!(recvbuf::Buffer, source::Integer, tag::Integer, comm::Comm, status::Union{Ref{Status},Nothing}) # int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source, # int tag, MPI_Comm comm, MPI_Status *status) - API.MPI_Recv(recvbuf.data, recvbuf.count, recvbuf.datatype, source, tag, comm, something(status, Consts.MPI_STATUS_IGNORE[])) + API.MPI_Recv(recvbuf.data, recvbuf.count, recvbuf.datatype, source, tag, comm, something(status, API.MPI_STATUS_IGNORE[])) return recvbuf.data end Recv!(recvbuf, source::Integer, tag::Integer, comm::Comm, status::Union{Ref{Status},Nothing}) = @@ -141,7 +141,7 @@ Returns a tuple of the object of type `T` and optionally the [`Status`](@ref) of # External links $(_doc_external("MPI_Recv")) """ -Recv(::Type{T}, comm::Comm, status=nothing; source=Consts.MPI_ANY_SOURCE[], tag=Consts.MPI_ANY_TAG[]) where {T} = +Recv(::Type{T}, comm::Comm, status=nothing; source=API.MPI_ANY_SOURCE[], tag=API.MPI_ANY_TAG[]) where {T} = Recv(T, source, tag, comm, status) function Recv(::Type{T}, source::Integer, tag::Integer, comm::Comm, status::Union{Ref{Status}, Nothing}) where T @@ -165,7 +165,7 @@ Completes a blocking receive of a serialized object from MPI rank `source` of co Returns the deserialized object and optionally the [`Status`](@ref) of the receive. """ -recv(comm::Comm, status=nothing; source::Integer=Consts.MPI_ANY_SOURCE[], tag::Integer=Consts.MPI_ANY_TAG[]) = +recv(comm::Comm, status=nothing; source::Integer=API.MPI_ANY_SOURCE[], tag::Integer=API.MPI_ANY_TAG[]) = recv(source, tag, comm, status) function recv(source::Integer, tag::Integer, comm::Comm, status::Union{Ref{Status}, Nothing}) stat = Probe(source, tag, comm) @@ -196,7 +196,7 @@ Returns the [`Request`](@ref) object for the nonblocking receive. # External links $(_doc_external("MPI_Irecv")) """ -Irecv!(recvbuf, comm::Comm; source::Integer=Consts.MPI_ANY_SOURCE[], tag::Integer=Consts.MPI_ANY_TAG[]) = +Irecv!(recvbuf, comm::Comm; source::Integer=API.MPI_ANY_SOURCE[], tag::Integer=API.MPI_ANY_TAG[]) = Irecv!(recvbuf, source, tag, comm) function Irecv!(buf::Buffer, source::Integer, tag::Integer, comm::Comm) req = Request() @@ -233,7 +233,7 @@ buffer `recvbuf` using message tag `recvtag`. Return a [`Status`](@ref) object. # External links $(_doc_external("MPI_Sendrecv")) """ -Sendrecv!(sendbuf, recvbuf, comm::MPI.Comm, status=nothing; dest::Integer, sendtag::Integer=0, source::Integer=Consts.MPI_ANY_SOURCE[], recvtag::Integer=Consts.MPI_ANY_TAG[]) = +Sendrecv!(sendbuf, recvbuf, comm::MPI.Comm, status=nothing; dest::Integer, sendtag::Integer=0, source::Integer=API.MPI_ANY_SOURCE[], recvtag::Integer=API.MPI_ANY_TAG[]) = Sendrecv!(sendbuf, dest, sendtag, recvbuf, source, recvtag, comm, status) function Sendrecv!(sendbuf::Buffer, dest::Integer, sendtag::Integer, @@ -244,7 +244,7 @@ function Sendrecv!(sendbuf::Buffer, dest::Integer, sendtag::Integer, # MPI_Comm comm, MPI_Status *status) API.MPI_Sendrecv(sendbuf.data, sendbuf.count, sendbuf.datatype, dest, sendtag, recvbuf.data, recvbuf.count, recvbuf.datatype, source, recvtag, - comm, something(status, Consts.MPI_STATUS_IGNORE[])) + comm, something(status, API.MPI_STATUS_IGNORE[])) return recvbuf.data end Sendrecv!(sendbuf, dest::Integer, sendtag::Integer, recvbuf, source::Integer, recvtag::Integer, comm::Comm, status::Union{Ref{Status}, Nothing}) = diff --git a/src/topology.jl b/src/topology.jl index f46dcf84f..ef695bd5b 100644 --- a/src/topology.jl +++ b/src/topology.jl @@ -53,7 +53,7 @@ function Cart_create(comm::Comm, dims; periodic = map(_->false, dims), reorder=f API.MPI_Cart_create(comm, length(dims), dims, periodic, reorder, comm_cart) comm_cart != COMM_NULL && finalizer(free, comm_cart) comm_cart -end +end """ rank = Cart_rank(comm::Comm, coords) @@ -78,9 +78,9 @@ end """ dims, periods, coords = Cart_get(comm::Comm) -Obtain information on the Cartesian topology of dimension `N` underlying the +Obtain information on the Cartesian topology of dimension `N` underlying the communicator `comm`. This is specified by two `Cint` arrays of `N` elements -for the number of processes and periodicity properties along each Cartesian dimension. +for the number of processes and periodicity properties along each Cartesian dimension. A third `Cint` array is returned, containing the Cartesian coordinates of the calling process. # External links @@ -172,14 +172,14 @@ function Cart_sub(comm::Comm, remain_dims) comm_sub end -struct Unweighted +struct Unweighted end -Base.cconvert(::Type{Ptr{Cint}}, ::Unweighted) = Consts.MPI_UNWEIGHTED[] +Base.cconvert(::Type{Ptr{Cint}}, ::Unweighted) = API.MPI_UNWEIGHTED[] const UNWEIGHTED = Unweighted() struct WeightsEmpty end -Base.cconvert(::Type{Ptr{Cint}}, ::WeightsEmpty) = Consts.MPI_WEIGHTS_EMPTY[] +Base.cconvert(::Type{Ptr{Cint}}, ::WeightsEmpty) = API.MPI_WEIGHTS_EMPTY[] const WEIGHTS_EMPTY = WeightsEmpty() """ @@ -230,7 +230,7 @@ Create a new communicator from a given directed graph topology, described by inc - `comm::Comm`: The communicator on which the distributed graph topology should be induced. - `sources::Vector{Cint}`: An array with the ranks for which this call will specify outgoing edges. - `degrees::Vector{Cint}`: An array with the number of outgoing edges for each entry in the sources array. -- `destinations::Vector{Cint}`: An array containing with lenght of the sum of the entries in the degrees array +- `destinations::Vector{Cint}`: An array containing with lenght of the sum of the entries in the degrees array describing the ranks towards the edges point. - `weights::Union{Vector{Cint}, Unweighted, WeightsEmpty}=MPI.UNWEIGHTED`: The edge weights of the specified edges. - `reorder::Bool=false`: If set true, then the MPI implementation can reorder the source and destination indices. @@ -310,7 +310,7 @@ Return the neighbors and edge weights of the calling process in a distributed gr associated to the edges of the outgoing edges of the calling process point. The length is exactly the outdegree returned by [`MPI.Dist_graph_neighbors_count`](@ref). -# Example +# Example Let us assume the following graph `0 <-3-> 1 -4-> 2`, then the process with rank 1 will require to preallocate a sources vector of length 1 and a destination vector of length 2. The call will fill the vectors as follows: @@ -327,8 +327,8 @@ julia> destination_weights [3,4] ``` -Note that the edge between ranks 0 and 1 can have a different weight depending on wether it is the -incoming edge "`(0,1)"` or the outgoing one "`(1,0)"`. +Note that the edge between ranks 0 and 1 can have a different weight depending on wether it is the +incoming edge "`(0,1)"` or the outgoing one "`(1,0)"`. # External links $(_doc_external("MPI_Dist_graph_neighbors")) @@ -338,7 +338,7 @@ function Dist_graph_neighbors!(graph_comm::Comm, sources::Vector{Cint}, source_w # int maxindegree, int sources[], int sourceweights[], # int maxoutdegree, int destinations[], int destweights[]) API.MPI_Dist_graph_neighbors(graph_comm, - length(sources), sources, source_weights, + length(sources), sources, source_weights, length(destinations), destinations, destination_weights) end @@ -349,14 +349,14 @@ Return the neighbors of the calling process in a distributed graph topology with # Arguments - `graph_comm::Comm`: The communicator of the distributed graph topology. -- `sources::Vector{Cint}`: A preallocated vector, which will be filled with the ranks of the +- `sources::Vector{Cint}`: A preallocated vector, which will be filled with the ranks of the processes whose edges pointing towards the calling process. The length is exactly the indegree returned by [`MPI.Dist_graph_neighbors_count`](@ref). - `destinations::Vector{Cint}`: A preallocated vector, which will be filled with the ranks of the processes towards which the edges of the calling process point. The length is exactly the outdegree returned by [`MPI.Dist_graph_neighbors_count`](@ref). -# Example +# Example Let us assume the following graph `0 <--> 1 --> 2`, then the process with rank 1 will require to preallocate a sources vector of length 1 and a destination vector of length 2. The call will fill the vectors as follows: diff --git a/test/test_cart_shift.jl b/test/test_cart_shift.jl index 287631624..5b8d91566 100644 --- a/test/test_cart_shift.jl +++ b/test/test_cart_shift.jl @@ -14,7 +14,7 @@ disp = 1 for i in 0:2 neighbors = MPI.Cart_shift(comm_cart, i, disp) - @test all(rank -> 0 <= rank < nnodes || rank == MPI.Consts.MPI_PROC_NULL[], neighbors) + @test all(rank -> 0 <= rank < nnodes || rank == MPI.API.MPI_PROC_NULL[], neighbors) end comm_cart = nothing diff --git a/test/test_ibarrier.jl b/test/test_ibarrier.jl index 058cc8fd0..83af155c1 100644 --- a/test/test_ibarrier.jl +++ b/test/test_ibarrier.jl @@ -2,7 +2,7 @@ using Test using MPI function check_for_query(comm) - is_message, status = MPI.Iprobe(MPI.Consts.MPI_ANY_SOURCE[], MPI.Consts.MPI_ANY_TAG[], comm) + is_message, status = MPI.Iprobe(MPI.API.MPI_ANY_SOURCE[], MPI.API.MPI_ANY_TAG[], comm) if is_message recv_id = status.source tag_ind = status.tag @@ -17,10 +17,10 @@ comm = MPI.COMM_WORLD myrank = MPI.Comm_rank(comm) mysize = MPI.Comm_size(comm) -# First rank will send, one-at-a-time, the rank + 4 to each other rank. +# First rank will send, one-at-a-time, the rank + 4 to each other rank. # They will then sum these and test if the sum is correct. Each rank > 0 # will be waiting at the Ibarrier for messages from 0 in order to test -# that the Ibarrier is working properly. +# that the Ibarrier is working properly. # They then communicate back to 0 when they have received all messages to # to allow it to reach the barrier. # @@ -37,11 +37,11 @@ if myrank == 0 rmsg = MPI.Recv!(dummy, comm; source=ii, tag=ii) end end - + all_done = false -localsum = 0 +localsum = 0 msg_num = 0 barrier_req = MPI.Ibarrier(comm) @@ -54,7 +54,7 @@ while !all_done global msg_num global myrank is_request, recv_id, tag_ind = check_for_query(comm) - if is_request + if is_request dummy = [0] rmsg = MPI.Recv!(dummy, comm; source=recv_id, tag=tag_ind) msg_num += 1 @@ -64,7 +64,7 @@ while !all_done end end # is_request all_done = MPI.Test(barrier_req) -end # !all_done +end # !all_done if myrank > 0 @test localsum == 10 * (myrank + 4) diff --git a/test/test_test.jl b/test/test_test.jl index e7d982923..e7b37448e 100644 --- a/test/test_test.jl +++ b/test/test_test.jl @@ -28,9 +28,9 @@ inds = MPI.Waitsome(reqs) for ind in inds (onedone,stat) = MPI.Test(reqs[ind], MPI.Status) @test onedone - @test MPI.Get_tag(stat) == MPI.Consts.MPI_ANY_TAG[] - @test MPI.Get_source(stat) == MPI.Consts.MPI_ANY_SOURCE[] - @test MPI.Get_error(stat) == MPI.Consts.MPI_SUCCESS[] + @test MPI.Get_tag(stat) == MPI.API.MPI_ANY_TAG[] + @test MPI.Get_source(stat) == MPI.API.MPI_ANY_SOURCE[] + @test MPI.Get_error(stat) == MPI.API.MPI_SUCCESS[] @test MPI.Get_count(stat, Float64) == 0 end @@ -38,9 +38,9 @@ done, ind = MPI.Testany(reqs) if done && !isnothing(ind) (onedone,stat) = MPI.Test(reqs[ind], MPI.Status) @test onedone - @test MPI.Get_tag(stat) == MPI.Consts.MPI_ANY_TAG[] - @test MPI.Get_source(stat) == MPI.Consts.MPI_ANY_SOURCE[] - @test MPI.Get_error(stat) == MPI.Consts.MPI_SUCCESS[] + @test MPI.Get_tag(stat) == MPI.API.MPI_ANY_TAG[] + @test MPI.Get_source(stat) == MPI.API.MPI_ANY_SOURCE[] + @test MPI.Get_error(stat) == MPI.API.MPI_SUCCESS[] @test MPI.Get_count(stat, Float64) == 0 end