-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Expand SnoopCompileCore.@snoopi to report _all MethodInstances_ that are inferred during a single inference call. #37535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Since Ref{} isn't available yet from inside Core.Compiler :)
|
I'm super not sure where the best places actually are to do the logging from within Julia. I just poked around putting print statements in a bunch of places until I found a spot that seems(?) reasonable. I'd super appreciate help / advice / suggestions on how best to do this! ❤️! Thanks in advance ~~ hopefully this is useful to others! :) |
|
I haven't had a chance to think about this in detail, but you're not the first person to wish for this. 👍 |
|
This might be better done with a custom |
- I _think_ this should get us all of the MethodInstances that are being inferred during inference of a caller function. - The old approach was missing some edges. - Also, this now presents that info via a dependency graph, which can be used to reverse-engineer which methods are responsible for what time
Thanks @Keno. If I'm not mistaken, isn't what you're describing already true of the behavior of julia> f(x) = x+3
f (generic function with 1 method)
julia> SnoopCompileCore.@snoopi begin
f(2)
end
1-element Array{Tuple{Float64,Core.MethodInstance},1}:
(0.0002541542053222656, MethodInstance for f(::Int64))
julia> SnoopCompileCore.@snoopi begin
f(2)
end
0-element Array{Tuple{Float64,Core.MethodInstance},1}
julia> If so, I think this is actually what we want, because we want to know for a given run exactly what ended up taking time in the compiler, not necessarily what functions are most expensive to compile from scratch (though that would also be useful to know). Is the above what you were referring to? Or were you referring to something else? Thanks! |
|
Question: Unless I've messed up my data collection, which is of course possible, in the example I just recorded it seems like there are hundreds of exact duplicate edges. I've added the logging inside julia/base/compiler/typeinfer.jl Lines 525 to 545 in be69119
That's inside the body of julia/base/compiler/typeinfer.jl Line 503 in be69119
And when I collected the data, I found that within a single top-level call to julia> [e for e in edges if last(e) == sorted_targets[1]]
144-element Vector{Pair{Core.MethodInstance,Core.MethodInstance}}:
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)
...
julia> unique([e for e in edges if last(e) == sorted_targets[1]])
1-element Vector{Pair{Core.MethodInstance,Core.MethodInstance}}:
MethodInstance for (::Base.var"#printstyled##kw")(::NamedTuple{(:color,),Tuple{Symbol}}, ::typeof(printstyled), ::String) => MethodInstance for #printstyled#779(::Bool, ::Symbol, ::typeof(printstyled), ::String)Out of the 6,212 edges I collected for one top-level function, there are only 145 unique edges, and only 118 unique MethodInstances. This also means that there are some MethodInstances being inferred from multiple parents. (There are 21 such cases, mostly with 2 callers, four with 3, and one with 5.) Is this expected? Based on reading the comments and the code, I thought that this should only be called if Am I misunderstanding this? Thanks! :) I figured I'd mention it here in case this is a bug / performance regression that could easily be fixed! :) |
|
And, actually, more evidence for the above: For the method instance in question, So I'm thinking that there's maybe a problem in the inference code, where it's not detecting duplicate nodes correctly, and it's redundantly inferring the same MethodInstances multiple times within the same inferable set! @JeffBezanson: Maybe this is also something we can take a look at together tomorrow when we meet up? :) EDIT: Although, hmm, maybe not: is EDIT EDIT: On a bigger example, where the original |
Before this PR, it reported only the entry MethodInstance:
After this PR, we want to be able to get all the MethodInstances that are (recursively) inferred during the inference to the top method instance.
Currently, it now looks like this:
But we're very open to other ideas for how best to represent this! :)
I think it might be super cool to return this as a DAG rather than a vector, so that we could maybe then work our way up from the leaves timing
code_typedon each of them one at a time to try to understand which function had the most exclusive time?This PR is basically applying the same trick we did in #37136 to get the full set of MethodInstances being compiled, rather than just the entry method instance.