Repository navigation
Pass the output type of tforeach positionally - #177
Conversation
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #177 +/- ##
==========================================
+ Coverage 90.24% 92.86% +2.62%
==========================================
Files 3 9 +6
Lines 82 729 +647
==========================================
+ Hits 74 677 +603
- Misses 8 52 +44 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
So one potential side-effect of this is that it slows down the serial fallback path when e.g. here's what I see using OhMyThreads, BenchmarkTools
tref = Ref{DataType}(Float64) # concrete type; the value is only known at run time
xs1 = 1:1; xs = 1:1000
@benchmark tmapreduce(sin, +, $xs1; outputtype = $tref[]) # serial, run-time T
@benchmark tmapreduce(sin, +, $xs; outputtype = $tref[]) # parallel, run-time T
@benchmark tmapreduce(sin, +, $xs; outputtype = Float64) # parallel, literal Tthe @inline function tmapreduce_positional(f::F, op::OP, Arrs, outputtype::Type,
scheduler, init, kwargs) where {F, OP}
# ... scheduler setup, checks, serial fallback: unchanged ...
else
_tmapreduce_typed(f, op, Arrs, outputtype, _scheduler, mapreduce_kwargs)
end
end
# function barrier: only the parallel path depends on the output type
@noinline function _tmapreduce_typed(f::F, op::OP, Arrs, ::Type{OutputType}, scheduler,
mapreduce_kwargs) where {F, OP, OutputType}
return _tmapreduce(f, op, Arrs, OutputType, scheduler, mapreduce_kwargs)
end |
Passed through keyword arguments, `outputtype = Nothing` is stored as a `DataType`, so `_tmapreduce` was compiled for every output type at once and a scheduler's implementation compiled the reduction path for every `tforeach` body, a loop without a result. `tforeach` now calls a positional entry point that `tmapreduce` shares, with `Nothing` as a constant. With ThreadTeams' team scheduler this takes the first loop of a new body from about 100 to 80 ms.
4771549 to
f0e43eb
Compare
Thanks, reproduced (6 ns → 470 ns). |
0.8.9 passes its output type to `Implementation._tmapreduce` the way the schedulers expect again (JuliaFolds2/OhMyThreads.jl#177), so the Enzyme rules work with it. 0.8.8 broke them (#71), and 0.8.7 has nothing over 0.8.9.
tforeachcallstmapreduce(...; kwargs..., init = nothing, outputtype = Nothing). Passed through keyword arguments,Nothingis stored in the keywordNamedTupleas aDataType, so_tmapreducegets compiled withOutputTypeunknown: for every output type at once. A scheduler implementation that branches onOutputType === Nothingthen compiles its reduction path for everytforeachbody too.tforeachnow calls a positional entry point,tmapreduce_positional, whichtmapreduceshares, withNothingas a constant. Behaviour doesn't change:tforeachstill ignoresinitandoutputtype.With ThreadTeams.jl's team scheduler this takes a new loop body's first
tforeachfrom about 100 to 80 ms of compilation.This also fixes ThreadTeams.jl's Enzyme tests on Julia ≥ 1.12, which 0.8.8 broke (a
CallingConventionMismatchErrorin its Enzyme rule forrun_chunks; they pass with this PR).