• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaParallel / MPI.jl / 16589599617

29 Jul 2025 07:29AM UTC coverage: 63.158%. Remained the same
16589599617

push

github

web-flow
Bump AMDGPU (#910)

1752 of 2774 relevant lines covered (63.16%)

4142.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.9
/src/nonblocking.jl
1
import Base: eltype
2

3

4
const SUCCESS = Cint(0)
5

6
@static if VERSION >= v"1.8"
7
    PROC_NULL::Cint = typemin(Cint)
8
    ANY_SOURCE::Cint = typemin(Cint)
9
    ANY_TAG::Cint = typemin(Cint)
10
end
11
add_load_time_hook!() do
12
    global PROC_NULL = API.MPI_PROC_NULL[]
2,032✔
13
    global ANY_SOURCE = API.MPI_ANY_SOURCE[]
2,032✔
14
    global ANY_TAG = API.MPI_ANY_TAG[]
2,032✔
15
end
16

17
"""
18
    MPI.PROC_NULL
19

20
A dummy value that can be used instead of a rank wherever a source or a
21
destination argument is required in a call. A send
22
"""
23
PROC_NULL
24

25
"""
26
    MPI.ANY_SOURCE
27

28
A wild card value for receive or probe operations that matches any source rank.
29
"""
30
ANY_SOURCE
31

32
"""
33
    MPI.ANY_TAG
34

35
A wild card value for receive or probe operations that matches any tag.
36
"""
37
ANY_TAG
38

39
"""
40
    MPI.Status
41

42
The status of an MPI receive communication. It has 3 accessible fields
43

44
- `source`: source of the received message
45
- `tag`: tag of the received message
46
- `error`: error code. This is only set if a function returns multiple statuses.
47

48
Additionally, the accessor function [`MPI.Get_count`](@ref) can be used to determine the
49
number of entries received.
50
"""
51
const Status = MPI_Status
52

53
const STATUS_ZERO = Status(map(zero,fieldtypes(Status))...)
54

55
function Base.getproperty(status::Status, name::Symbol)
2,056✔
56
    name ≡ :error && return status.MPI_ERROR
4,146✔
57
    name ≡ :source && return status.MPI_SOURCE
3,917✔
58
    name ≡ :tag && return status.MPI_TAG
3,160✔
59
    return getfield(status, name)
1,968✔
60
end
61
function Base.setproperty!(status::Status, name::Symbol, x)
×
62
    name ≡ :error && return (status.MPI_ERROR = x)
×
63
    name ≡ :source && return (status.MPI_SOURCE = x)
×
64
    name ≡ :tag && return (status.MPI_TAG = x)
×
65
    return setfield!(status, name, x)
×
66
end
67

68
# TODO: I don't think we need `SentinelPtr`; we should remove it
69
Base.cconvert(::Type{Ptr{Status}}, x::SentinelPtr) = x
×
70
Base.unsafe_convert(::Type{Ptr{Status}}, x::SentinelPtr) = reinterpret(Ptr{Status}, x)
×
71

72
# TODO: Deprecate these functions
73
Get_source(status::Status) = Int(status.source)
167✔
74
Get_tag(status::Status) = Int(status.tag)
167✔
75
Get_error(status::Status) = Int(status.error)
124✔
76

77
"""
78
    MPI.AbstractRequest
79

80
An abstract type for Julia objects wrapping MPI Requests objects, which
81
represent non-blocking MPI communication operations. The following
82
implementations provided in MPI.jl
83

84
- [`Request`](@ref): this is the default request type.
85
- [`UnsafeRequest`](@ref): similar to `Request`, but does not maintain a
86
  reference to the underlying communication buffer.
87
- `MultiRequestItem`: created by calling `getindex` on a [`MultiRequest`](@ref)
88
  / [`UnsafeMultiRequest`](@ref) object, which efficiently stores a collection
89
  of requests.
90

91
# How request objects are used
92

93
A request object can be passed to non-blocking communication operations, such as
94
[`MPI.Isend`](@ref) and [`MPI.Irecv!`](@ref). If no object is provided, then an
95
[`MPI.Request`](@ref) is used.
96

97
The status of a Request can be checked by the [`Wait`](@ref) and [`Test`](@ref)
98
functions or their mœultiple-request variants, which will deallocate the request
99
once it is determined to be complete.
100

101
Alternatively, it will be deallocated by calling `MPI.free` or at finalization,
102
meaning that it is safe to ignore the request objects if the status of the
103
communication can be checked by other means.
104

105
In certain cases, the operation can also be cancelled by [`Cancel!`](@ref).
106

107
# Implementing new request types
108

109
Subtypes `R <: AbstractRequest` should define the methods for the following
110
functions:
111

112
- C conversion functions to `MPI_Request` and `Ptr{MPI_Request}`:
113
  - `Base.cconvert(::Type{MPI_Request}, req::R)` /
114
    `Base.unsafe_convert(::Type{MPI_Request}, req::R)`
115
  - `Base.cconvert(::Type{Ptr{MPI_Request}}, req::R)` /
116
    `Base.unsafe_convert(::Type{Ptr{MPI_Request}}, req::R)``
117
- setbuffer!(req::R, val)`: keep a reference to the communication buffer `val`.
118
  If `val == nothing`, then clear the reference.
119
"""
120
abstract type AbstractRequest end
121

122
"""
123
    isnull(req::AbstractRequest)
124

125
Is `req` is a null request.
126
"""
127
function isnull(req::AbstractRequest)
139,820✔
128
    creq = Base.cconvert(MPI_Request, req)
322,463✔
129
    GC.@preserve creq Base.unsafe_convert(MPI_Request, creq) == API.MPI_REQUEST_NULL[]
322,463✔
130
end
131

132
function Base.show(io::IO, req::AbstractRequest)
451✔
133
    if get(io, :typeinfo, Any) != typeof(req)
451✔
134
        print(io, typeof(req), ": ")
451✔
135
    end
136
    if isnull(req)
451✔
137
        print(io, "null request")
×
138
    else
139
        ref_flag = Ref(Cint(0))
451✔
140
        ref_status = Ref(STATUS_ZERO)
451✔
141
        API.MPI_Request_get_status(req, ref_flag, ref_status)
451✔
142
        if ref_flag[] != 0
451✔
143
            status = ref_status[]
328✔
144
            if status.source == API.MPI_ANY_SOURCE[] && status.tag == API.MPI_ANY_TAG[] && status.error == API.MPI_SUCCESS[]
496✔
145
                print(io, "inactive request")
328✔
146
            else
147
                print(io, "completed request, source = ", status.source, ", tag = ", status.tag)
×
148
                if status.error != API.MPI_SUCCESS[]
×
149
                    print(io, ", error = ", status.error)
×
150
                end
151
            end
152
        else
153
            print(io, "incomplete request")
123✔
154
        end
155
    end
156
end
157

158
function free(req::AbstractRequest)
1,261✔
159
    if !isnull(req) && !MPI.Finalized()
1,261✔
160
        # int MPI_Request_free(MPI_Request *req)
161
        API.MPI_Request_free(req)
164✔
162
    end
163
    setbuffer!(req, nothing)
1,261✔
164
    return nothing
1,261✔
165
end
166

167

168
"""
169
    MPI.Request()
170

171
The default MPI Request object, representing a non-blocking communication. This also contains a
172
reference to the buffer used in the communication to ensure it isn't garbage-collected
173
during communication.
174

175
See [`AbstractRequest`](@ref) for more information.
176
"""
177
mutable struct Request <: AbstractRequest
178
    val::MPI_Request
3,011✔
179
    buffer
180
end
181
function Request()
1,617✔
182
    req = Request(API.MPI_REQUEST_NULL[], nothing)
3,011✔
183
    return finalizer(free, req)
3,010✔
184
end
185

186
setbuffer!(req::Request, val) = req.buffer = val
4,566✔
187

188
Base.cconvert(::Type{MPI_Request}, request::Request) = request
320,906✔
189
Base.unsafe_convert(::Type{MPI_Request}, request::Request) = request.val
320,906✔
190
Base.unsafe_convert(::Type{Ptr{MPI_Request}}, request::Request) = convert(Ptr{MPI_Request}, pointer_from_objref(request))
314,844✔
191

192

193
const REQUEST_NULL = Request(API.MPI_REQUEST_NULL[], nothing)
194
add_load_time_hook!(LoadTimeHookSetVal(REQUEST_NULL, API.MPI_REQUEST_NULL))
195

196
"""
197
    MPI.UnsafeRequest()
198

199
Similar to [`MPI.Request`](@ref), but does not maintain a reference to the
200
underlying communication buffer. This may have improve performance by reducing
201
memory allocations.
202

203
!!! warning
204

205
    The user should ensure that another reference to the communication buffer is
206
    maintained so that it is not cleaned up by the garbage collector
207
    before the communication operation is complete.
208

209
    For example
210
    ```julia
211
    buf = MPI.Buffer(zeros(10))
212
    GC.@preserve buf begin
213
        req = MPI.Isend(buf, comm, UnsafeRequest(); rank=1)
214
        # ...
215
        MPI.Wait(req)
216
    end
217
"""
218
mutable struct UnsafeRequest <: AbstractRequest
219
    val::MPI_Request
220
end
221

222
function UnsafeRequest()
×
223
    req = UnsafeRequest(API.MPI_REQUEST_NULL[])
×
224
    return finalizer(free, req)
×
225
end
226
setbuffer!(req::UnsafeRequest, val) = nothing
×
227

228
Base.cconvert(::Type{MPI_Request}, request::UnsafeRequest) = request
×
229
Base.unsafe_convert(::Type{MPI_Request}, request::UnsafeRequest) = request.val
×
230
Base.unsafe_convert(::Type{Ptr{MPI_Request}}, request::UnsafeRequest) = convert(Ptr{MPI_Request}, pointer_from_objref(request))
×
231

232

233
# abstract element type to work around lack of cyclic type definitions
234
# https://github.com/JuliaLang/julia/issues/269
235
abstract type AbstractMultiRequest <: AbstractVector{AbstractRequest}
236
end
237

238

239
"""
240
    MPI.MultiRequest(n::Integer=0)
241

242
A collection of MPI Requests. This is useful when operating on multiple MPI
243
requests at the same time. `MultiRequest` objects can be passed directly to
244
[`MPI.Waitall`](@ref), [`MPI.Testall`](@ref), etc.
245

246
`req[i]` will return a `MultiRequestItem` which
247
adheres to the [`AbstractRequest`] interface.
248

249
# Usage
250
```julia
251
reqs = MPI.MultiRequest(n)
252
for i = 1:n
253
    MPI.Isend(buf, comm, reqs[i]; rank=dest[i])
254
end
255
MPI.Waitall(reqs)
256
```
257
"""
258
struct MultiRequest <: AbstractMultiRequest
259
    vals::Vector{MPI_Request}
84✔
260
    buffers::Vector{Any}
261
end
262
MultiRequest(n::Integer=0) =
84✔
263
    MultiRequest(MPI_Request[API.MPI_REQUEST_NULL[] for _ = 1:n], Any[nothing for _ = 1:n])
264

265
function update!(reqs::MultiRequest, i::Integer)
646✔
266
    if isnull(reqs[i])
1,246✔
267
        setbuffer!(reqs[i], nothing)
381✔
268
    end
269
    return nothing
1,246✔
270
end
271
function update!(reqs::MultiRequest)
323✔
272
    foreach(i -> update!(reqs, i), 1:length(reqs))
2,492✔
273
    return nothing
623✔
274
end
275

276

277
"""
278
    MPI.UnsafeMultiRequest(n::Integer=0)
279

280
Similar to [`MPI.MultiRequest`](@ref), except that it does not maintain
281
references to the underlying communication buffers. The same caveats apply as
282
[`MPI.UnsafeRequest`](@ref).
283
"""
284
struct UnsafeMultiRequest <: AbstractMultiRequest
285
    vals::Vector{MPI_Request}
43✔
286
end
287
UnsafeMultiRequest(n::Integer=0) =
43✔
288
    UnsafeMultiRequest(MPI_Request[API.MPI_REQUEST_NULL[] for _ = 1:n])
289
update!(reqs::UnsafeMultiRequest, i::Integer) = nothing
×
290
update!(reqs::UnsafeMultiRequest) = nothing
80✔
291

292
struct MultiRequestItem{MR <: AbstractMultiRequest} <: AbstractRequest
293
    multireq::MR
3,528✔
294
    idx::Int
295
end
296

297
Base.eltype(::Type{MR}) where {MR<:AbstractMultiRequest} = MultiRequestItem{MR}
×
298
Base.length(mreq::AbstractMultiRequest) = length(mreq.vals)
1,758✔
299
Base.size(mreq::AbstractMultiRequest) = (length(mreq),)
168✔
300
Base.@propagate_inbounds function Base.getindex(mreq::AbstractMultiRequest,i::Integer)
1,370✔
301
    @boundscheck checkbounds(mreq.vals,i)
2,389✔
302
    MultiRequestItem(mreq, i)
2,389✔
303
end
304

305
function free(mreq::AbstractMultiRequest)
41✔
306
    for req in mreq
82✔
307
        free(req)
102✔
308
    end
63✔
309
    return nothing
41✔
310
end
311

312
Base.cconvert(::Type{MPI_Request}, req::MultiRequestItem) = req
2,008✔
313
Base.unsafe_convert(::Type{MPI_Request}, req::MultiRequestItem) = @inbounds req.multireq.vals[req.idx]
2,008✔
314
Base.unsafe_convert(::Type{Ptr{MPI_Request}}, req::MultiRequestItem) =
336✔
315
    convert(Ptr{MPI_Request}, pointer(req.multireq.vals, req.idx))
316

317
setbuffer!(req::MultiRequestItem{MultiRequest}, val) =
631✔
318
    @inbounds req.multireq.buffers[req.idx] = val
319
setbuffer!(req::MultiRequestItem{UnsafeMultiRequest}, val) =
40✔
320
    nothing
321

322

323
function Base.resize!(mreq::MultiRequest, n::Integer)
43✔
324
    m = length(mreq)
43✔
325
    # free any requests being removed
326
    for i = n+1:m
66✔
327
        free(mreq[i])
×
328
    end
329
    resize!(mreq.vals, n)
43✔
330
    resize!(mreq.buffers, n)
43✔
331
    for i = m+1:n
63✔
332
        # initialize
333
        mreq.vals[i] = API.MPI_REQUEST_NULL[]
86✔
334
        mreq.buffers[i] = nothing
106✔
335
    end
69✔
336
    return mreq
43✔
337
end
338
function Base.resize!(mreq::UnsafeMultiRequest, n::Integer)
43✔
339
    m = length(mreq)
43✔
340
    # free any requests being removed
341
    for i = n+1:m
66✔
342
        free(mreq[i])
×
343
    end
344
    resize!(mreq.vals, n)
43✔
345
    for i = m+1:n
63✔
346
        # initialize
347
        mreq.vals[i] = API.MPI_REQUEST_NULL[]
106✔
348
    end
69✔
349
    return mreq
43✔
350
end
351

352

353
"""
354
    Probe(comm::Comm;
355
            source::Integer=MPI.ANY_SOURCE, tag::Integer=MPI.ANY_TAG)
356
    status = Probe(comm::Comm, MPI.Status;
357
        source::Integer=MPI.ANY_SOURCE, tag::Integer=MPI.ANY_TAG)
358

359
Blocks until there is a message that can be received matching `source`, `tag` and
360
`comm`. Optionally returns the corresponding [`Status`](@ref) object.
361

362
# External links
363
$(_doc_external("MPI_Probe"))
364
"""
365
Probe(comm::Comm, status=nothing; source::Integer=API.MPI_ANY_SOURCE[], tag::Integer=API.MPI_ANY_TAG[]) =
×
366
    Probe(source, tag, comm, status)
367
function Probe(source::Integer, tag::Integer, comm::Comm, status::Union{Ref{Status}, Nothing})
×
368
    API.MPI_Probe(source, tag, comm, something(status, API.MPI_STATUS_IGNORE[]))
×
369
    return nothing
×
370
end
371
function Probe(source::Integer, tag::Integer, comm::Comm, ::Type{Status})
×
372
    status = Ref(STATUS_ZERO)
×
373
    API.MPI_Probe(source, tag, comm, status)
×
374
    return status[]
×
375
end
376

377
# kept for compatibility
378
Probe(source::Integer, tag::Integer, comm::Comm) =
×
379
    Probe(source, tag::Integer, comm::Comm, Status)
380

381
"""
382
    ismsg = Iprobe(comm::Comm;
383
            source::Integer=MPI.ANY_SOURCE, tag::Integer=MPI.ANY_TAG)
384
    ismsg, status = Iprobe(comm::Comm, MPI.Status;
385
            source::Integer=MPI.ANY_SOURCE, tag::Integer=MPI.ANY_TAG)
386

387
Checks if there is a message that can be received matching `source`, `tag` and
388
`comm`. If so, returns `ismsg = true`. The `Status` argument additionally
389
returns the [`Status`](@ref) of the completed request.
390

391

392
# External links
393
$(_doc_external("MPI_Iprobe"))
394
"""
395
Iprobe(comm::Comm, status=nothing; source::Integer=API.MPI_ANY_SOURCE[], tag::Integer=API.MPI_ANY_TAG[]) =
621,014✔
396
    Iprobe(source, tag, comm, status)
397
function Iprobe(source::Integer, tag::Integer, comm::Comm, status::Union{Ref{Status}, Nothing})
133,368✔
398
    flag = Ref{Cint}()
310,507✔
399
    API.MPI_Iprobe(source, tag, comm, flag, something(status, API.MPI_STATUS_IGNORE[]))
310,507✔
400
    return flag[] != 0
310,507✔
401
end
402
function Iprobe(source::Integer, tag::Integer, comm::Comm, ::Type{Status})
133,368✔
403
    status = Ref(STATUS_ZERO)
310,507✔
404
    ismsg = Iprobe(source, tag, comm, status)
310,507✔
405
    return ismsg, status[]
310,507✔
406
end
407

408
# kept for compatibility
409
function Iprobe(source::Integer, tag::Integer, comm::Comm)
×
410
    ismsg, status = Iprobe(source, tag, comm, Status)
×
411
    return ismsg, (ismsg ? status : nothing)
×
412
end
413

414
"""
415
    MPI.Get_count(status::Status, T)
416

417
The number of entries received. `T` should match the argument provided by the receive call that set the status variable.
418

419
If the number of entries received exceeds the limits of the count parameter, then it returns `MPI_UNDEFINED`.
420

421
# External links
422
$(_doc_external("MPI_Get_count"))
423
"""
424
function Get_count(stat::Status, datatype::Datatype)
132✔
425
    count = Ref{Cint}()
245✔
426
    API.MPI_Get_count(Ref(stat), datatype, count)
245✔
427
    Int(count[])
245✔
428
end
429
Get_count(stat::Status, ::Type{T}) where {T} = Get_count(stat, Datatype(T))
245✔
430

431

432
"""
433
    Wait(req::AbstractRequest)
434
    status = Wait(req::AbstractRequest, Status)
435

436
Block until the request `req` is complete and deallocated.
437

438
The `Status` argument returns the [`Status`](@ref) of the completed request.
439

440
# External links
441
$(_doc_external("MPI_Wait"))
442
"""
443
function Wait(req::AbstractRequest, status::Union{Ref{Status}, Nothing}=nothing)
66✔
444
    # int MPI_Wait(MPI_Request *request, MPI_Status *status)
445
    API.MPI_Wait(req, something(status, API.MPI_STATUS_IGNORE[]))
86✔
446
    # only clear the buffer for non-persistent requests
447
    if isnull(req)
43✔
448
        setbuffer!(req, nothing)
43✔
449
    end
450
    return nothing
43✔
451
end
452
function Wait(req::AbstractRequest, ::Type{Status})
×
453
    status = Ref(STATUS_ZERO)
×
454
    Wait(req, status)
×
455
    return status[]
×
456
end
457

458
"""
459
    flag = Test(req::AbstractRequest)
460
    flag, status = Test(req::AbstractRequest, Status)
461

462
Check if the request `req` is complete. If so, the request is deallocated and `flag = true` is returned. Otherwise `flag = false`.
463

464
The `Status` argument additionally returns the [`Status`](@ref) of the completed request.
465

466
# External links
467
$(_doc_external("MPI_Test"))
468
"""
469
function Test(req::AbstractRequest, status::Union{Ref{Status}, Nothing}=nothing)
622,592✔
470
    flag = Ref{Cint}()
622,752✔
471
    # int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status)
472
    API.MPI_Test(req, flag, something(status, API.MPI_STATUS_IGNORE[]))
311,419✔
473
    if isnull(req)
311,419✔
474
        setbuffer!(req, nothing)
375✔
475
    end
476
    return flag[] != 0
311,419✔
477
end
478
function Test(req::AbstractRequest, ::Type{Status})
86✔
479
    status = Ref(STATUS_ZERO)
86✔
480
    flag = Test(req, status)
86✔
481
    return flag, status[]
86✔
482
end
483

484

485
"""
486
    RequestSet(requests::Vector{Request})
487
    RequestSet() # create an empty RequestSet
488

489
A wrapper for an array of `Request`s that can be used to reduce intermediate memory
490
allocations in [`Waitall`](@ref), [`Testall`](@ref), [`Waitany`](@ref), [`Testany`](@ref),
491
[`Waitsome`](@ref) or [`Testsome`](@ref).
492

493
Consider using a [`MultiRequest`](@ref) or [`UnsafeMultiRequest`](@ref) instead.
494
"""
495
struct RequestSet <: AbstractVector{Request}
496
    requests::Vector{Request}
1,445✔
497
    vals::Vector{MPI_Request}
498
end
499

500
function RequestSet(requests::Vector{Request})
810✔
501
    n = length(requests)
1,445✔
502
    vals = Vector{MPI_Request}(undef, n)
2,169✔
503
    for i = 1:n
2,080✔
504
        vals[i] = requests[i].val
4,515✔
505
    end
3,040✔
506
    return RequestSet(requests, vals)
1,445✔
507
end
508
RequestSet() = RequestSet(Request[])
43✔
509

510
Base.length(reqs::RequestSet) = length(reqs.requests)
3,499✔
511
Base.getindex(reqs::RequestSet, i::Integer) = reqs.requests[i]
3,926✔
512
function Base.setindex!(reqs::RequestSet, req::Request, i::Integer)
×
513
    reqs.vals[i] = req.val
×
514
    reqs.requests[i] = req
×
515
end
516

517
function Base.push!(reqs::RequestSet, req::Request)
×
518
    push!(reqs.vals, req.val)
×
519
    push!(reqs.requests, req)
×
520
end
521

522
function update!(reqs::RequestSet, i::Integer)
2,084✔
523
    req = reqs[i]
3,926✔
524
    req.val = reqs.vals[i]
3,926✔
525
    isnull(req) && (req.buffer = nothing)
4,459✔
526
end
527
update!(reqs::RequestSet) = foreach(i -> update!(reqs, i), 1:length(reqs))
8,009✔
528

529

530
"""
531
    Waitall(reqs::AbstractVector{Request}[, statuses::Vector{Status}])
532
    statuses = Waitall(reqs::AbstractVector{Request}, Status)
533

534
Block until all active requests in the array `reqs` are complete.
535

536
The optional `statuses` or `Status` argument can be used to obtain the return
537
[`Status`](@ref) of each request.
538

539
# See also
540
- [`RequestSet`](@ref) can be used to minimize allocations
541

542
# External links
543
$(_doc_external("MPI_Waitall"))
544
"""
545
function Waitall(reqs::Union{AbstractMultiRequest, RequestSet}, statuses::Union{AbstractVector{Status},Nothing}=nothing)
2,177✔
546
    n = length(reqs)
2,612✔
547
    n == 0 && return nothing
1,349✔
548
    @assert isnothing(statuses) || length(statuses) >= n
1,263✔
549
    # int MPI_Waitall(int count, MPI_Request array_of_requests[],
550
    #                 MPI_Status array_of_statuses[])
551
    API.MPI_Waitall(n, reqs.vals, something(statuses, API.MPI_STATUSES_IGNORE[]))
1,263✔
552
    update!(reqs)
3,281✔
553
    return nothing
1,263✔
554
end
555
function Waitall(reqs::Union{AbstractMultiRequest, RequestSet}, ::Type{Status})
66✔
556
    statuses = Array{Status}(undef, length(reqs))
109✔
557
    Waitall(reqs, statuses)
86✔
558
    return statuses
86✔
559
end
560
Waitall(reqs::AbstractVector{Request}, args...) = Waitall(RequestSet(reqs), args...)
931✔
561

562

563
"""
564
    flag = Testall(reqs::AbstractVector{Request}[, statuses::Vector{Status}])
565
    flag, statuses = Testall(reqs::AbstractVector{Request}, Status)
566

567
Check if all active requests in the array `reqs` are complete. If so, the
568
requests are deallocated and `true` is returned. Otherwise no requests are
569
modified, and `false` is returned.
570

571
The optional `statuses` or `Status` argument can be used to obtain the return
572
[`Status`](@ref) of each request.
573

574
# See also
575
- [`RequestSet`](@ref) can be used to minimize allocations
576

577
# External links
578
$(_doc_external("MPI_Testall"))
579
"""
580
function Testall(reqs::Union{AbstractMultiRequest, RequestSet}, statuses::Union{AbstractVector{Status},Nothing}=nothing)
1,128✔
581
    n = length(reqs)
1,168✔
582
    flag = Ref{Cint}()
584✔
583
    @assert isnothing(statuses) || length(statuses) >= n
584✔
584
    # int MPI_Testall(int count, MPI_Request array_of_requests[], int *flag,
585
    #                 MPI_Status array_of_statuses[])
586
    API.MPI_Testall(n, reqs.vals, flag, something(statuses, API.MPI_STATUSES_IGNORE[]))
584✔
587
    update!(reqs)
1,082✔
588
    return flag[] != 0
584✔
589
end
590
function Testall(reqs::Union{AbstractMultiRequest, RequestSet}, ::Type{Status})
×
591
    statuses = Array{Status}(undef, length(reqs))
×
592
    flag = Testall(reqs, statuses)
×
593
    return flag, statuses
×
594
end
595
Testall(reqs::Vector{Request}, args...) = Testall(RequestSet(reqs), args...)
×
596

597
"""
598
    i = Waitany(reqs::AbstractVector{Request}[, status::Ref{Status}])
599
    i, status = Waitany(reqs::AbstractVector{Request}, Status)
600

601
Blocks until one of the requests in the array `reqs` is complete: if more than
602
one is complete, one is chosen arbitrarily. The request is deallocated and the
603
(1-based) index `i` of the completed request is returned.
604

605
If there are no active requests, then `i = nothing`.
606

607
The optional `status` argument can be used to obtain the return [`Status`](@ref)
608
of the request.
609

610
# See also
611
- [`RequestSet`](@ref) can be used to minimize allocations
612

613
# External links
614
$(_doc_external("MPI_Waitany"))
615
"""
616
function Waitany(reqs::Union{AbstractMultiRequest, RequestSet}, status::Union{Ref{Status}, Nothing}=nothing)
264✔
617
    ref_idx = Ref{Cint}()
344✔
618
    n = length(reqs)
172✔
619
    # int MPI_Waitany(int count, MPI_Request array_of_requests[], int *index,
620
    #                 MPI_Status *status)
621
    API.MPI_Waitany(n, reqs.vals, ref_idx, something(status, API.MPI_STATUS_IGNORE[]))
172✔
622
    idx = ref_idx[]
172✔
623
    idx == API.MPI_UNDEFINED[] && return nothing
172✔
624
    i = Int(idx) + 1
172✔
625
    update!(reqs, i)
172✔
626
    return i
172✔
627
end
628
function Waitany(reqs::Union{AbstractMultiRequest, RequestSet}, ::Type{Status})
×
629
    status = Ref(STATUS_ZERO)
×
630
    i = Waitany(reqs, status)
×
631
    return i, status[]
×
632
end
633
Waitany(reqs::Vector{Request}, args...) = Waitany(RequestSet(reqs), args...)
172✔
634

635
"""
636
    flag, idx = Testany(reqs::AbstractVector{Request}[, status::Ref{Status}])
637
    flag, idx, status = Testany(reqs::AbstractVector{Request}, Status)
638

639
Checks if any one of the requests in the array `reqs` is complete.
640

641
If one or more requests are complete, then one is chosen arbitrarily, deallocated. `flag =
642
true` and its (1-based) index `idx` is returned.
643

644
If there are no completed requests, then `flag = false` and `idx = nothing` is returned.
645

646
If there are no active requests, `flag = true` and `idx = nothing`.
647

648
The optional `status` argument can be used to obtain the return [`Status`](@ref) of the request.
649

650
# See also
651
- [`RequestSet`](@ref) can be used to minimize allocations
652

653
# External links
654
$(_doc_external("MPI_Testany"))
655
"""
656
function Testany(reqs::Union{AbstractMultiRequest, RequestSet}, status::Union{Ref{Status}, Nothing}=nothing)
46✔
657
    ref_idx = Ref{Cint}()
94✔
658
    rflag = Ref{Cint}()
43✔
659
    n = length(reqs)
43✔
660
    # int MPI_Testany(int count, MPI_Request array_of_requests[], int *index,
661
    #                 int *flag, MPI_Status *status)
662
    API.MPI_Testany(n, reqs.vals, ref_idx, rflag, something(status, API.MPI_STATUS_IGNORE[]))
43✔
663
    idx = ref_idx[]
43✔
664
    flag = rflag[] != 0
43✔
665
    idx == API.MPI_UNDEFINED[] && return flag, nothing
43✔
666
    i = Int(idx) + 1
16✔
667
    update!(reqs, i)
16✔
668
    return flag, i
16✔
669
end
670
function Testany(reqs::Union{AbstractMultiRequest, RequestSet}, ::Type{Status})
×
671
    status = Ref(STATUS_ZERO)
×
672
    flag, i = Testany(reqs, status)
×
673
    return flag, i, status[]
×
674
end
675
Testany(reqs::Vector{Request}, args...) = Testany(RequestSet(reqs), args...)
43✔
676

677
"""
678
    inds = Waitsome(reqs::AbstractVector{Request}[, statuses::Vector{Status}])
679

680
Block until at least one of the active requests in the array `reqs` is complete.
681
The completed requests are deallocated, and an array `inds` of their indices in
682
`reqs` is returned.
683

684
If there are no active requests, then `inds = nothing`.
685

686
The optional `statuses` argument can be used to obtain the return
687
[`Status`](@ref) of each completed request.
688

689
# See also
690
- [`RequestSet`](@ref) can be used to minimize allocations
691

692
# External links
693
$(_doc_external("MPI_Waitsome"))
694
"""
695
function Waitsome(reqs::Union{AbstractMultiRequest, RequestSet}, statuses::Union{AbstractVector{Status},Nothing}=nothing)
327✔
696
    ref_nout = Ref{Cint}()
387✔
697
    n = length(reqs)
215✔
698
    idxs = Vector{Cint}(undef, n)
330✔
699
    @assert isnothing(statuses) || length(statuses) >= n
215✔
700

701
    # int MPI_Waitsome(int incount, MPI_Request array_of_requests[],
702
    #                  int *outcount, int array_of_indices[],
703
    #                  MPI_Status array_of_statuses[])
704
    API.MPI_Waitsome(n, reqs.vals, ref_nout, idxs, something(statuses, API.MPI_STATUSES_IGNORE[]))
215✔
705
    nout = Int(ref_nout[])
215✔
706
    # This can happen if there were no valid requests
707
    nout == API.MPI_UNDEFINED[] && return nothing
215✔
708
    update!(reqs)
301✔
709
    return [Int(idxs[i]) + 1 for i = 1:nout]
172✔
710
end
711
function Waitsome(reqs::Union{AbstractMultiRequest, RequestSet}, ::Type{Status})
43✔
712
    statuses = Array{Status}(undef, length(reqs))
66✔
713
    inds = Waitsome(reqs, statuses)
43✔
714
    resize!(statuses, isnothing(inds) ? 0 : length(inds))
63✔
715
    return inds, statuses
43✔
716
end
717
Waitsome(reqs::Vector{Request}, args...) = Waitsome(RequestSet(reqs), args...)
129✔
718

719
"""
720
    inds = Testsome(reqs::AbstractVector{Request}[, statuses::Vector{Status}])
721

722
Similar to [`Waitsome`](@ref) except that if no operations have completed it
723
will return an empty array.
724

725
If there are no active requests, then the function returns `nothing`.
726

727
The optional `statuses` argument can be used to obtain the return
728
[`Status`](@ref) of each completed request.
729

730
# See also
731
- [`RequestSet`](@ref) can be used to minimize allocations
732

733
# External links
734
$(_doc_external("MPI_Testsome"))
735
"""
736
function Testsome(reqs::Union{AbstractMultiRequest, RequestSet}, statuses::Union{AbstractVector{Status},Nothing}=nothing)
43✔
737
    ref_nout = Ref{Cint}()
43✔
738
    n = length(reqs)
43✔
739
    idxs = Vector{Cint}(undef, n)
66✔
740
    @assert isnothing(statuses) || length(statuses) >= n
43✔
741

742
    # int MPI_Testsome(int incount, MPI_Request array_of_requests[],
743
    #                  int *outcount, int array_of_indices[],
744
    #                  MPI_Status array_of_statuses[])
745
    API.MPI_Testsome(n, reqs.vals, ref_nout, idxs, something(statuses, API.MPI_STATUSES_IGNORE[]))
43✔
746
    nout = Int(ref_nout[])
43✔
747
    # This can happen if there were no valid requests
748
    nout == API.MPI_UNDEFINED[] && return nothing
43✔
749
    update!(reqs)
×
750
    return [Int(idxs[i]) + 1 for i = 1:nout]
×
751
end
752
function Testsome(reqs::Union{AbstractMultiRequest, RequestSet}, ::Type{Status})
43✔
753
    statuses = Array{Status}(undef, length(reqs))
66✔
754
    inds = Testsome(reqs, statuses)
43✔
755
    resize!(statuses, isnothing(inds) ? 0 : length(inds))
63✔
756
    return inds, statuses
43✔
757
end
758
Testsome(reqs::Vector{Request}, args...) = Testsome(RequestSet(reqs), args...)
43✔
759

760
"""
761
    Cancel!(req::Request)
762

763
Marks a pending [`Irecv!`](@ref) operation for cancellation (cancelling a [`Isend`](@ref),
764
while supported in some implementations, is deprecated as of MPI 3.1). Note that the
765
request is not deallocated, and can still be queried using the test or wait functions.
766

767
# External links
768
$(_doc_external("MPI_Cancel"))
769
"""
770
function Cancel!(req::AbstractRequest)
43✔
771
    # int MPI_Cancel(MPI_Request *request)
772
    API.MPI_Cancel(req)
43✔
773
    nothing
20✔
774
end
775

776
"""
777
    Base.wait(req::MPI.Request)
778

779
Wait for an MPI request to complete. Unlike [`MPI.Wait`](@ref), it will yield to other Julia tasks resulting in a cooperative wait.
780
"""
781
function Base.wait(req::MPI.Request)
92✔
782
    while !MPI.Test(req)
258✔
783
        yield()
86✔
784
    end
46✔
785
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc