Terminal interaction and precompile times

Somewhat related to the other threads on precompile times (such as thread and thread), I was wondering about (perceived) long precompilation for very simple and common operations. These seem to have gotten worse as well, from 1.12 onwards.

For example, with 1.13-beta1 (but similar on 1.12), entering using in the REPL when nothing is loaded yet, followed by tab completion is quick, but after loading DataFrames subsequently entering using<tab> involves seconds-long stalls:

melis@blackbox 15:34:/tmp$ j +1.13 --trace-compile-timing --trace-compile=stderr --project
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.13.0-beta1 (2026-01-12)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org release
|__/                   |

julia> u#=    9.1 ms =# precompile(Tuple{typeof(REPL.REPLCompletions.named_completion), REPL.REPLCompletions.KeywordCompletion})
#=    3.4 ms =# precompile(Tuple{typeof(REPL.REPLCompletions.named_completion), REPL.REPLCompletions.ModuleCompletion})
#=    8.2 ms =# precompile(Tuple{typeof(Base.Order.lt), Base.Order.By{typeof(REPL.REPLCompletions.named_completion_completion), Base.Order.ForwardOrdering}, REPL.REPLCompletions.ModuleCompletion, REPL.REPLCompletions.KeywordCompletion})
#=    5.8 ms =# precompile(Tuple{typeof(Base.Order.lt), Base.Order.Lt{Base.Sort.var"#_sort!##10#_sort!##11"{Base.Order.By{typeof(REPL.REPLCompletions.named_completion_completion), Base.Order.ForwardOrdering}}}, REPL.REPLCompletions.ModuleCompletion, REPL.REPLCompletions.KeywordCompletion})
#=    7.0 ms =# precompile(Tuple{typeof(Base.Order.lt), Base.Order.Lt{Base.Sort.var"#_sort!##10#_sort!##11"{Base.Order.By{typeof(REPL.REPLCompletions.named_completion_completion), Base.Order.ForwardOrdering}}}, REPL.REPLCompletions.ModuleCompletion, REPL.REPLCompletions.ModuleCompletion})
#=    5.6 ms =# precompile(Tuple{typeof(Base.Order.lt), Base.Order.By{typeof(REPL.REPLCompletions.named_completion_completion), Base.Order.ForwardOrdering}, REPL.REPLCompletions.ModuleCompletion, REPL.REPLCompletions.ModuleCompletion})
julia> us#=  161.6 ms =# precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:color,), Tuple{Symbol}}, typeof(Base.printstyled), Base.Terminals.TTYTerminal, String})
ing#=    5.1 ms =# precompile(Tuple{typeof(Base.Terminals.cmove_left), Base.Terminals.TTYTerminal, Int64})
julia> using #=    7.9 ms =# precompile(Tuple{typeof(Base.Order.lt), Base.Order.By{typeof(REPL.REPLCompletions.named_completion_completion), Base.Order.ForwardOrdering}, REPL.REPLCompletions.PackageCompletion, REPL.REPLCompletions.PackageCompletion})
#=    6.3 ms =# precompile(Tuple{typeof(Base.Order.lt), Base.Order.Lt{Base.Sort.var"#_sort!##10#_sort!##11"{Base.Order.By{typeof(REPL.REPLCompletions.named_completion_completion), Base.Order.ForwardOrdering}}}, REPL.REPLCompletions.PackageCompletion, REPL.REPLCompletions.PackageCompletion})
julia> using DataFrames
#=    2.8 ms =# precompile(Tuple{typeof(Base.getindex), Base.RefValue{Ptr{UInt8}}})
#=    2.6 ms =# precompile(Tuple{typeof(Base.unsafe_convert), Type{Ptr{Ptr{UInt8}}}, Base.RefValue{Ptr{UInt8}}})
#=    4.4 ms =# precompile(Tuple{typeof(Base.indexed_iterate), Pair{Any, Bool}, Int64})
#=    5.1 ms =# precompile(Tuple{typeof(Base.indexed_iterate), Pair{Any, Bool}, Int64, Int64})

julia> #= 5153.6 ms =# precompile(Tuple{typeof(REPL.LineEdit.refresh_multi_line), Base.Terminals.TerminalBuffer, Base.Terminals.UnixTerminal, Union{REPL.LineEdit.PrefixSearchState, REPL.LineEdit.PromptState}}) # recompile
#=    7.0 ms =# precompile(Tuple{typeof(Base.get), Base.TTY, Symbol, Bool}) # recompile
#=    2.8 ms =# precompile(Tuple{typeof(Base.:(var"==")), Nothing, Bool})
#=  178.1 ms =# precompile(Tuple{typeof(Base.AnnotatedDisplay.ansi_write), typeof(Base.write), Base.IOContext{Base.Terminals.TerminalBuffer}, Base.SubString{Base.AnnotatedString{String}}}) # recompile
julia> using#=    4.3 ms =# precompile(Tuple{typeof(Base.indexed_iterate), Tuple{Nothing, Nothing}, Int64, Int64})
#= 1003.6 ms =# precompile(Tuple{typeof(Core.kwcall), NamedTuple{names, T} where T<:Tuple where names, typeof(REPL.LineEdit.complete_line), REPL.REPLCompletionProvider, REPL.LineEdit.PromptState, Module}) # recompile
julia> using

If I load StaticVectors instead of DataFrames then the slow compiles don’t occur, so it appears to be something related to the latter package.

Another example is the common case of getting some error printed when trying to run a script from the command-line (here, incorrect script file name), which is very sluggish as well, in printing the error:

melis@blackbox 15:36:/tmp$ j +1.13 --trace-compile-timing --trace-compile=stderr --project does-not-exist.jl
#=    9.0 ms =# precompile(Tuple{typeof(Base.scrub_repl_backtrace), Array{Union{Ptr{Nothing}, Base.InterpreterIP}, 1}})
#=    4.6 ms =# precompile(Tuple{typeof(Base.getindex), Pair{Symbol, Bool}, Int64})
#=  543.9 ms =# precompile(Tuple{typeof(Base.display_error), Base.TTY, Base.ExceptionStack})
ERROR: #= 1063.6 ms =# precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:backtrace,), Tuple{Bool}}, typeof(Base.showerror), Base.IOContext{Base.TTY}, Base.SystemError, Array{Base.StackTraces.StackFrame, 1}})
SystemError: opening file "/tmp/does-not-exist.jl": No such file or directory#=    6.0 ms =# precompile(Tuple{Base.var"#_backtrace_remove_kwcall_frames!##0#_backtrace_remove_kwcall_frames!##1", Tuple{Base.StackTraces.StackFrame, Int64}})
#=    4.4 ms =# precompile(Tuple{typeof(Base.indexed_iterate), Tuple{Base.StackTraces.StackFrame, Int64}, Int64})
#=    4.4 ms =# precompile(Tuple{typeof(Base.indexed_iterate), Tuple{Base.StackTraces.StackFrame, Int64}, Int64, Int64})
#=    3.4 ms =# precompile(Tuple{Base.var"#846#847", Tuple{Base.StackTraces.StackFrame, Int64}})
#=    3.4 ms =# precompile(Tuple{Base.MappingRF{Base.var"#846#847", Base.BottomRF{typeof(Base.add_sum)}}, Int64, Tuple{Base.StackTraces.StackFrame, Int64}})
#=    3.9 ms =# precompile(Tuple{Base.var"#848#849", Tuple{Base.StackTraces.StackFrame, Int64}})

Stacktrace:
 [1] #=   11.6 ms =# precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:use_color,), Tuple{Bool}}, typeof(Base.print_type_bicolor), Base.IOContext{Base.GenericIOBuffer{Memory{UInt8}}}, Type})
include(mod::Module, _path::String)
   @ Base ./Base.jl:309
 [2] exec_options(opts::Base.JLOptions)
   @ Base ./client.jl:344
 [3] _start()
   @ Base ./client.jl:577

There might be very different causes to these two, but both of them (for me) are in the same category, i.e. basic terminal-based interaction with Julia. Having such precompile latencies pop up there doesn’t help in user experience, nor in the perception of Julia to new users. So I was wondering if these are known issues that perhaps don’t get much priority, or if there is something else going on?

2 Likes

Dataframes or one of it’s deps is invalidating the REPL

1 Like

Maybe this is related?

Indeed it’s caused by invalidations. Should be fixed in the next 1.13 beta and 1.12 patch release: JuliaSyntax:force specialize on function in `parse_brackets` by KristofferC · Pull Request #60403 · JuliaLang/julia · GitHub

2 Likes