You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In JuliaData/DataFrames.jl#2691 I needed to use Ref{Any} trick to avoid excessive specialization. Unfortunately I was not able to achieve the required level of despecialization using @nospecialize. The issue is quite complex and we discussed with @nalimilan a lot what to do with it. Since we really do not understand in full how to avoid specialization I ask the question here (as on Slack it probably will get quickly lost).
The problem is that @nospecialize does not guarantee that the argument is not specialized. There are cases when not having this is prohibitive (as each additional compilation of method instance is costly in itself). Here is an MWE using MethodAnalysis.jl:
julia> using MethodAnalysis
julia> @noinline f(@nospecialize(x)) = map(x, [1,2,3])
f (generic function with 1 method)
julia> g(x) = f(x)
g (generic function with 1 method)
julia> g(sin);
julia> methodinstances(f)
2-element Vector{Core.MethodInstance}:
MethodInstance for f(::Function)
MethodInstance for f(::Any)
julia> g(Int);
julia> methodinstances(f)
3-element Vector{Core.MethodInstance}:
MethodInstance for f(::Function)
MethodInstance for f(::Any)
MethodInstance for f(::Type)
julia> g(Float64);
julia> methodinstances(f)
3-element Vector{Core.MethodInstance}:
MethodInstance for f(::Function)
MethodInstance for f(::Any)
MethodInstance for f(::Type)
and I get 3 method instances of f instead of 1 as I wanted.
Now in a fresh session additionally this happens:
julia> using MethodAnalysis
julia> @noinline f(@nospecialize(x)) = map(x, [1,2,3])
f (generic function with 1 method)
julia> g(x::Base.Callable) = f(x)
g (generic function with 1 method)
julia> g(sin);
julia> methodinstances(f)
2-element Vector{Core.MethodInstance}:
MethodInstance for f(::Function)
MethodInstance for f(::Any)
julia> g(Int);
julia> methodinstances(f)
3-element Vector{Core.MethodInstance}:
MethodInstance for f(::Function)
MethodInstance for f(::Any)
MethodInstance for f(::Type{Int64})
julia> g(Float64);
julia> methodinstances(f)
4-element Vector{Core.MethodInstance}:
MethodInstance for f(::Function)
MethodInstance for f(::Any)
MethodInstance for f(::Type{Int64})
MethodInstance for f(::Type{Float64})
and this time it is even worse - for each type passed a new method instance is generated.
I have more examples if needed, but they all boil down to one issue: how to tell the compiler that unconditionally only one method instance should be generated for a given argument (as commented above in JuliaData/DataFrames.jl#2691 we ended up using Ref{Any} to guarantee this, but this is kind of ugly and maybe there is a better way to do it).
The text was updated successfully, but these errors were encountered:
I've been caught by the same thing (see #35131). @nospecialize blocks deeper forms of specialization (e.g., LLVM IR) but not inference. If you want to also block inference, you can do this:
g(x::Base.Callable) =f(Base.inferencebarrier(x))
All inferencebarrier currently does is the equivalent of this:
g(x::Base.Callable) =f(Ref{Any}(x)[])
Just pushing it into a Ref{Any} and immediately popping it out again is enough to have inference give up trying to infer the argument type that you're calling callee with. Perhaps in the long run inferencebarrier might become an intrinsic. (The fear might be, what if inference gets so smart it can figure out the type of x even after temporarily stashing in a Ref{Any}?)
In JuliaData/DataFrames.jl#2691 I needed to use
Ref{Any}
trick to avoid excessive specialization. Unfortunately I was not able to achieve the required level of despecialization using@nospecialize
. The issue is quite complex and we discussed with @nalimilan a lot what to do with it. Since we really do not understand in full how to avoid specialization I ask the question here (as on Slack it probably will get quickly lost).The problem is that
@nospecialize
does not guarantee that the argument is not specialized. There are cases when not having this is prohibitive (as each additional compilation of method instance is costly in itself). Here is an MWE using MethodAnalysis.jl:and I get 3 method instances of
f
instead of 1 as I wanted.Now in a fresh session additionally this happens:
and this time it is even worse - for each type passed a new method instance is generated.
I have more examples if needed, but they all boil down to one issue: how to tell the compiler that unconditionally only one method instance should be generated for a given argument (as commented above in JuliaData/DataFrames.jl#2691 we ended up using
Ref{Any}
to guarantee this, but this is kind of ugly and maybe there is a better way to do it).The text was updated successfully, but these errors were encountered: