TypeAnalysis: skip redundant remove/insert in AugmentWithJuliaObjectType - #3199
Open
maximilian-gelbrecht wants to merge 1 commit into
Open
maximilian-gelbrecht wants to merge 1 commit into
maximilian-gelbrecht wants to merge 1 commit into
Conversation
AugmentWithJuliaObjectType runs on every getAnalysis call. For a tracked
pointer type it unconditionally did remove({-1}); remove({0});
insert({-1}, Pointer), and for each Julia pointer field of a struct
remove({off}); insert({off}, Pointer). TypeTree::insert walks the whole
offset map, so on large TypeTrees (pointers to big Julia structs) each
query paid O(map) although the tree already carried the result after the
first augmentation.
Check the exact keys first (O(log n)) and return early when the tree
already has the post-condition. The end state of the tree is unchanged.
Measured on SpeedyWeather.jl (BarotropicModel time_step!, reverse mode,
Julia 1.12, on top of EnzymeAD#3186/EnzymeAD#3187/EnzymeAD#3188): 123.5 s -> 111.0 s, gradient
bit-identical.
Member
|
The other alternative is #3197 which is caching the types |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is something that Fable found when analysing compile times of SpeedyWeather gradients in Julia 1.12. I chatted with @vchuravy about this.
Claude summary:
TypeAnalysis: skip redundant remove/insert in
AugmentWithJuliaObjectTypeWhat
AugmentWithJuliaObjectType(enzyme/Enzyme/TypeAnalysis/TypeAnalysis.cpp) is called fromTypeAnalyzer::getAnalysis, i.e. on every type query, whenEnzymeJuliaAddrLoadis set. It marks Julia objectpointers in the
TypeTree:remove({-1}); remove({0}); insert({-1}, Pointer),remove({off}); insert({off}, Pointer).It does this unconditionally, although after the first call the tree already carries exactly that result.
TypeTree::insertiterates over the whole offset map ("check if there is an existing match"), so every later queryon a large tree — a pointer to a big Julia struct has one entry per field offset — pays O(map size) for nothing.
This PR checks the exact keys first (an O(log n)
map::find) and returns early when the post-condition alreadyholds:
{-1}isPointerand there is no{0}entry,{off}is alreadyPointer.The resulting tree is identical to what the unconditional remove/insert produces; only the redundant work is skipped.
About 15 added lines, no new state.
Why
With #3186/#3187/#3188 in place, profiling reverse-mode compilation of a Julia atmospheric model
(SpeedyWeather.jl, Julia 1.12, LLVM 18) shows activity analysis dominated by
i.e. half of the activity-analysis time is this redundant re-augmentation.
Measured
SpeedyWeather.jl
BarotropicModeltime_step!, reverse mode, Julia 1.12.6, Apple M3, Enzyme core v0.0.292 +#3186/#3187/#3188 as the baseline:
On the same model's larger
PrimitiveWetModelstep the change is one of two needed to get through activity analysisat all (the other being a memoised
isNoNeedincalculateUnusedValuesInFunction, sent separately).Testing