Skip to content

Specialize any, all, count and findall on the predicate, and infer any and all as Bool - #191

Merged
maleadt merged 2 commits into
JuliaGPU:mainfrom
AzamatB:ab/specialize-predicates
Oct 29, 2026
Merged

maleadt merged 2 commits into
JuliaGPU:mainfrom
AzamatB:ab/specialize-predicates

Conversation

@AzamatB

@AzamatB AzamatB commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Since GPUArrays 12, Base's any, all and findall of GPU arrays go through AK, and on main a warm call still runs inference every time:

julia> f(x) = any(>(0), x);   # x::CuVector{Int32}, 10_000 elements

julia> @time f(x)
  0.000113 seconds (62 allocations: 2.828 KiB, 0.52% compilation time: 100% of which was recompilation)

any, all, count, findall and most of the internal methods they call only pass the predicate on, so Julia compiles them for pred::Function. In that code, check_bool_result's Base.promote_op(pred, eltype(v)) can't fold and runs inference on each call. This PR annotates the predicate as pred::F ... where {F} in those methods, as the reductions already do with f::F, op::OP. A warm call then compiles nothing, and allocates about half as much on the host: on an RTX 5080, any(>(0), x) goes from 63 allocations (2.9 KB) and a median of 12.3–12.7 µs to 48 allocations (1.5 KB) and 11.6–11.9 µs, and AK.any(isnan, x) on 10,000 Float32s from 12.1–12.5 µs to 11.4–11.6 µs.

Separately, since #189 the tunings are looked up behind Base.inferencebarrier. Auto() picks a GPU's predicate algorithm, ConcurrentWrite or ViaReduce, from the tuning, so the plan doesn't infer, and neither does the result: Base.infer_return_type(all, Tuple{typeof(isfinite), CuVector{Float64, CUDA.DeviceMemory}}) is Any on main, and so is every caller that returns or uses the result, e.g. checkbounds(Bool, x, i::CuVector{Int32}). Hiding the tuning is intended (it avoids invalidations when loading a backend), so any and all now assert that their result is a Bool, which every algorithm returns. Run-time dispatch of the algorithm stays. The other operations that use tunings are not affected: reductions, scans, sorts, count and findall still infer with Auto() on CUDA, because their tuning only picks values or the algorithm's type doesn't change the result type.

The tests check that a warm call of any, all and findall by dynamic dispatch compiles nothing, and that any and all infer with each algorithm, including Auto(). Both fail on main (the second only on GPUs). The CPU tests (--cpu --cpu-ka) and the CUDA tests for the predicates, findall and the reductions pass on Julia 1.12, and the new tests also pass on 1.10.

sort!'s by has the same problem (promote_op(by, ...) in the sort setup still runs inference on each call). That's left for a separate PR.

@AzamatB AzamatB changed the title Specialize any, all, count and findall on the predicate Specialize any, all, count and findall on the predicate, and infer any and all as Bool Oct 28, 2026
@AzamatB AzamatB closed this Oct 28, 2026
@AzamatB AzamatB reopened this Oct 28, 2026
These methods, and most of the internal ones they call, only pass the
predicate on, so Julia compiles them for any `Function`. In that code,
`check_bool_result`'s `promote_op` runs inference on every call, which
Julia reports as recompilation, and which costs allocations and a
fraction of a microsecond per call. Since GPUArrays 12, Base's `any`,
`all` and `findall` of GPU arrays take this path.

Name the predicate's type in every method that takes it, as the
reductions do, and test that a warm call compiles nothing.
Since JuliaGPU#189 looks up the tunings behind an inference barrier, `Auto()`
picks a GPU's predicate algorithm (`ConcurrentWrite` or `ViaReduce`)
from a value that inference does not see. The plan then does not infer,
and neither does the result: `any` and `all` of a GPU array infer as
`Any`, and so do callers of Base's `any` and `all` on one that return
or use the result, e.g. `checkbounds(Bool, x, i::CuVector)`.

Every algorithm returns a `Bool`, so assert it.
@maleadt
maleadt force-pushed the ab/specialize-predicates branch from 6a9a350 to 584ec2f Compare October 28, 2026 09:16
@maleadt

maleadt commented Oct 28, 2026

Copy link
Copy Markdown
Member

Thanks. Rebased and slightly reworked.

@maleadt
maleadt merged commit eb27308 into JuliaGPU:main Oct 29, 2026
17 checks passed
@AzamatB
AzamatB deleted the ab/specialize-predicates branch October 29, 2026 12:57
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