Skip to content

Understanding and reducing invalidation caused by CxxWrap #278

@fingolfin

Description

@fingolfin

So I run into https://discourse.julialang.org/t/new-tools-for-reducing-compiler-latency/52882 today and started reading https://julialang.org/blog/2021/01/precompile_tutorial/ as well as https://timholy.github.io/SnoopCompile.jl/stable/snoopr/#invalidations

Still got a lot to learn, but some basic tests already seem to indicate that CxxWrap has a lot room for improvement there -- note that this is not improvements that affect that load time of CxxWrap, but rather of packages using it. While that already got a lot better in Julia 1.6/1.7, there is still room to improvement.

Here's a sample run, listing 8226 invalidations:

$ julia-master
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.7.0-DEV.219 (2021-01-05)
 _/ |\__'_|_|_|\__'_|  |  Commit 399f8ba175* (0 days old master)
|__/                   |

julia> using SnoopCompileCore

julia> invalidations = @snoopr using CxxWrap;

julia> length(invalidations)
8226

julia> using SnoopCompile

julia> trees = invalidation_trees(invalidations);

julia> trees[end]
inserting convert(to_type::Type{Any}, x::CxxWrap.CxxWrapCore.SmartPointer{DerivedT}) where DerivedT in CxxWrap.CxxWrapCore at /Users/mhorn/.julia/packages/CxxWrap/ZOkSN/src/CxxWrap.jl:272 invalidated:
   backedges: 1: superseding convert(::Type{Any}, x) in Base at essentials.jl:204 with MethodInstance for convert(::Type{Any}, ::Any) (1229 children)

Turns out the top offender (which is at the end, and shown above) is a convert method for converting to Any, which was already removed by my PR #265 in September -- but apparently no CxxWrap release was made since then, meaning this performance improvement has not yet been released to the general public.

Again, fixing this may not affect CxxWrap's startup speed, but it does impact other code (see e.g. the issue linked in PR #265).

Here's another bad one:

julia> method_invalidations = trees[9]
inserting convert(::Type{T1}, p::CxxWrap.CxxWrapCore.SmartPointer{DerivedT}) where {BaseT, T1<:BaseT, DerivedT<:BaseT} in CxxWrap.CxxWrapCore at /Users/mhorn/.julia/packages/CxxWrap/ZOkSN/src/CxxWrap.jl:269 invalidated:
   mt_backedges:   1: signature Tuple{typeof(convert), Type{Symbol}, Any} triggered MethodInstance for Pair{Symbol, Base.IRShow.var"#33#35"}(::Any, ::Any) (0 children)
                   2: signature Tuple{typeof(convert), Type{Base.IRShow.var"#33#35"}, Any} triggered
...
                 379: signature Tuple{typeof(convert), Type{REPL.LineEdit.ModeState}, Any} triggered MethodInstance for setindex!(::IdDict{REPL.LineEdit.TextInterface, REPL.LineEdit.ModeState}, ::Any, ::Any) (66 children)
                 380: signature Tuple{typeof(convert), Type{Symbol}, Any} triggered MethodInstance for merge(::NamedTuple{(), Tuple{}}, ::Base.Iterators.Pairs) (255 children)

This is caused by the following method:

function Base.convert(::Type{T1}, p::SmartPointer{DerivedT}) where {BaseT,T1 <: BaseT, DerivedT <: BaseT}
  return cxxupcast(T1, p[])[]
end

If I am not mistaken, one possible choice for BaseT is Any, so the above code is effectively equivalent to this:

function Base.convert(::Type{S}, p::SmartPointer{T}) where {S, T}
  return cxxupcast(S, p[])[]
end

And so in particular, it also covers this special case, which seem highly problematic for the same reasons as discussed in issue #258, and beyond:

function Base.convert(::Type{Any}, p::SmartPointer{T}) where {T}
  return cxxupcast(Any, p[])[]
end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions