JuliaIO / FileIO.jl

Main Package for IO, loading all different kind of files
http://juliaio.github.io/FileIO.jl/
Other
216 stars 78 forks source link

Large amount of invalidations on nightly #396

Closed serenity4 closed 5 days ago

serenity4 commented 1 month ago

In nightly, loading FileIO results in lots of invalidations related to StyledStrings, see the following case:

(@v1.12) pkg> activate --temp
  Activating new project at `/tmp/jl_uxMxkY`

(jl_uxMxkY) pkg> add FileIO
   Resolving package versions...
    Updating `/tmp/jl_uxMxkY/Project.toml`
  [5789e2e9] + FileIO v1.16.3
    Updating `/tmp/jl_uxMxkY/Manifest.toml`
  [5789e2e9] + FileIO v1.16.3
  [ae029012] + Requires v1.3.0
  [0dad84c5] + ArgTools v1.1.2
  [56f22d72] + Artifacts v1.11.0
  [2a0f44e3] + Base64 v1.11.0
  [ade2ca70] + Dates v1.11.0
  [f43a241f] + Downloads v1.6.0
  [7b1f6079] + FileWatching v1.11.0
  [dc6e5ff7] + JuliaSyntaxHighlighting v1.12.0
  [b27032c2] + LibCURL v0.6.4
  [76f85450] + LibGit2 v1.11.0
  [8f399da3] + Libdl v1.11.0
  [56ddb016] + Logging v1.11.0
  [d6f4376e] + Markdown v1.11.0
  [ca575930] + NetworkOptions v1.2.0
  [44cfe95a] + Pkg v1.12.0
  [de0858da] + Printf v1.11.0
  [9a3f8284] + Random v1.11.0
  [ea8e919c] + SHA v0.7.0
  [f489334b] + StyledStrings v1.11.0
  [fa267f1f] + TOML v1.0.3
  [a4e569a6] + Tar v1.10.0
  [cf7118a7] + UUIDs v1.11.0
  [4ec0a83e] + Unicode v1.11.0
  [deac9b47] + LibCURL_jll v8.6.0+0
  [e37daf67] + LibGit2_jll v1.8.0+0
  [29816b5a] + LibSSH2_jll v1.11.0+1
  [c8ffd9c3] + MbedTLS_jll v2.28.6+0
  [14a3606d] + MozillaCACerts_jll v2024.3.11
  [83775a58] + Zlib_jll v1.3.1+0
  [8e850ede] + nghttp2_jll v1.60.0+0
  [3f19e933] + p7zip_jll v17.5.0+0

(jl_uxMxkY) pkg> precompile

julia> using SnoopCompileCore

julia> invs = @snoop_invalidations using FileIO;

julia> using SnoopCompile

julia> trees = invalidation_trees(invs)
3-element Vector{SnoopCompile.MethodInvalidations}:
 inserting displaysize(t::REPL.Terminals.UnixTerminal) @ REPL.Terminals ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/REPL/src/Terminals.jl:149 invalidated:
   backedges: 1: superseding displaysize(io::IO) @ Base stream.jl:568 with MethodInstance for displaysize(::IO) (50 children)
              2: superseding displaysize(io::IO) @ Base stream.jl:568 with MethodInstance for displaysize(::IO) (1 children)
              3: superseding displaysize(io::IO) @ Base stream.jl:568 with MethodInstance for displaysize(::IO) (1 children)

 inserting displaysize(::REPL.Terminals.TextTerminal) @ REPL.Terminals ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/REPL/src/Terminals.jl:46 invalidated:
   backedges: 1: superseding displaysize(io::IO) @ Base stream.jl:568 with MethodInstance for displaysize(::IO) (50 children)
              2: superseding displaysize(io::IO) @ Base stream.jl:568 with MethodInstance for displaysize(::IO) (1 children)
              3: superseding displaysize(io::IO) @ Base stream.jl:568 with MethodInstance for displaysize(::IO) (1 children)

 inserting read(s::Stream, nb) @ FileIO ~/.julia/packages/FileIO/xOKyx/src/types.jl:142 invalidated:
   mt_backedges: 1: signature Tuple{typeof(read), Any, Type{Base.AnnotatedString{String}}} triggered MethodInstance for Base._join_preserve_annotations(::Tuple{Any, String}, ::String, ::String) (0 children)
                 2: signature Tuple{typeof(read), Any, Type{Base.AnnotatedString{String}}} triggered MethodInstance for Base._join_preserve_annotations(::Tuple{Vararg{Symbol}}, ::String) (0 children)
                 3: signature Tuple{typeof(read), Any, Type{Base.AnnotatedString{String}}} triggered MethodInstance for Base._join_preserve_annotations(::Vector{Any}, ::String) (8069 children)

julia> versioninfo()
Julia Version 1.12.0-DEV.1040
Commit cf4c30accd9 (2024-08-12 13:10 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 32 × 13th Gen Intel(R) Core(TM) i9-13900F
  WORD_SIZE: 64
  LLVM: libLLVM-18.1.7 (ORCJIT, alderlake)
Threads: 32 default, 0 interactive, 32 GC (on 32 virtual cores)
Environment:
  JULIA_INFO_COLOR = green

As can be seen in the last invalidation tree, https://github.com/JuliaIO/FileIO.jl/blob/4c930733f74bc9658daa9ad98b94cb39eab785bf/src/types.jl#L157 triggers the invalidation of 8k+ children. In practice this causes lags of a few seconds in the REPL when typing common commands for the first time after loading FileIO (pkg> st and pkg> resolve particularly so). The cause is perhaps related to join on AnnotatedString as discussed already in https://github.com/KristofferC/OhMyREPL.jl/issues/355. I'm not sure if there is something to be done in FileIO or if this is something to address in Base or StyledStrings.

cc @tecosaur

tecosaur commented 1 month ago

At a glance it looks like:

serenity4 commented 1 month ago

Redefining Base.read(s::Stream, nb) as Base.read(s::Stream, nb::Integer) only shifts the invalidation to Base.read(s::Stream, args...) defined in the same file, so that fix isn't enough.

After experimenting, I believe the invalidation is caused by defining read(io::T, ...) where T is not an IO; I guess so far all io types implementing read with 2+ arguments subtype Base.IO. The invalidations get fixed if we make Stream <: IO. I submitted a PoC PR to see if this is a solution that can be deemed acceptable.

serenity4 commented 1 month ago

the signature should be Tuple{typeof(read), Base.AnnotatedIOBuffer, Type{Base.AnnotatedString{String}}} not Tuple{typeof(read), Any, Type{Base.AnnotatedString{String}}}

I agree, the io argument within the relevant part of Base._join_preserve_annotations clearly is inferrable to a Base.AnnotatedIOBuffer, I have no idea why the wider signature invalidates this callsite.