Skip to content
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

Test performance regression in UnicodePlots with julia 1.11.0-alpha2 #53688

Open
t-bltg opened this issue Mar 10, 2024 · 16 comments
Open

Test performance regression in UnicodePlots with julia 1.11.0-alpha2 #53688

t-bltg opened this issue Mar 10, 2024 · 16 comments

Comments

@t-bltg
Copy link
Contributor

t-bltg commented Mar 10, 2024

I have a little test case used to monitor allocations regression and runtime performance in UnicodePlots CI (with some tolerance): https://github.com/JuliaPlots/UnicodePlots.jl/blob/main/test/tst_io.jl#L67-L69.

It's been working flawlessly since julia 1.6 and up-to julia 1.10.2, but since 1.11.0-alpha1 there seems to be a massive regression in time performance (8ms vs 0.3ms before) and slightly more allocations (500kB vs 356kB before), resulting in CI failure such as the following:
https://github.com/JuliaPlots/UnicodePlots.jl/actions/runs/8173876886/job/22347317855#step:6:375

@KristofferC
Copy link
Member

Can you profile it? Potentially fixed by JuliaLang/Pkg.jl#3823.

@t-bltg
Copy link
Contributor Author

t-bltg commented Mar 10, 2024

Thanks, running from the REPL doesn't regress locally, so you are probably right about JuliaLang/Pkg.jl#3823 !
I'll keep an eye on the next alpha or beta version of 1.11.0 then ...

using UnicodePlots
let p = heatmap(collect(1:30) * collect(1:30)')
  string(p; color = true)  # 1st pass - ttfp
  GC.enable(false)
  stats = @timed string(p; color = true)  # repeated !
  GC.enable(true)
  @show stats.bytes stats.time
end
# stats.bytes = 372920 stats.time = 0.000797776 (1.11.0-alpha1)
# stats.bytes = 355704 stats.time = 0.000682859 (1.10.2)

@t-bltg t-bltg changed the title Runtime performance regression in UnicodePlots and julia 1.11-alpha1 Runtime performance regression in UnicodePlots and julia 1.11.0-alpha1 Mar 10, 2024
@t-bltg t-bltg changed the title Runtime performance regression in UnicodePlots and julia 1.11.0-alpha1 Test runtime performance regression in UnicodePlots and julia 1.11.0-alpha1 Mar 11, 2024
@t-bltg t-bltg changed the title Test runtime performance regression in UnicodePlots and julia 1.11.0-alpha1 Test performance regression in UnicodePlots with julia 1.11.0-alpha1 Mar 11, 2024
@t-bltg
Copy link
Contributor Author

t-bltg commented Mar 20, 2024

AFAIK this is still broken on 1.11.0-alpha2, running pkg> test UnicodePlots locally.

@IanButterworth
Copy link
Member

Yeah a profile would help here. You'd need to do it in the test suite itself

@t-bltg
Copy link
Contributor Author

t-bltg commented Mar 20, 2024

Added in the test suite:

p = heatmap(collect(1:30) * collect(1:30)')
string(p; color = true)  # 1st pass
GC.enable(false)
Profile.init(; n=10^9, delay=1e-7)
Profile.clear()
@profile string(p; color = true) 
Profile.print()
GC.enable(true)

Here is the Profile output on 1.10.2:

Overhead ╎ [+additional indent] Count File:Line; Function
=========================================================
   ╎473 @Base/client.jl:552; _start()
   ╎ 473 @Base/client.jl:291; exec_options(opts::Base.JLOptions)
   ╎  473 @Base/boot.jl:385; eval
   ╎   473 @Base/client.jl:489; include(fname::String)
   ╎    473 @Base/loading.jl:2136; _include(mapexpr::Function, mod::Module, _path::String)
   ╎     473 @Base/loading.jl:2076; include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String)
   ╎    ╎ 473 @Base/boot.jl:385; eval
   ╎    ╎  473 @Base/env.jl:257; withenv(f::var"#1#2", keyvals::Pair{String, String})
   ╎    ╎   473 @UnicodePlots/test/runtests.jl:115; (::var"#1#2")()
   ╎    ╎    473 @TimerOutputs/src/TimerOutput.jl:237; macro expansion
   ╎    ╎     473 @UnicodePlots/test/runtests.jl:105; macro expansion
   ╎    ╎    ╎ 473 @Test/src/Test.jl:1577; macro expansion
   ╎    ╎    ╎  473 @UnicodePlots/test/runtests.jl:105; macro expansion
   ╎    ╎    ╎   473 @Base/client.jl:489; include
   ╎    ╎    ╎    473 @Base/loading.jl:2136; _include(mapexpr::Function, mod::Module, _path::String)
   ╎    ╎    ╎     473 @Base/loading.jl:2076; include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String)
   ╎    ╎    ╎    ╎ 473 @Base/boot.jl:385; eval
   ╎    ╎    ╎    ╎  473 @UnicodePlots/test/tst_io.jl:60; top-level scope
   ╎    ╎    ╎    ╎   473 @Test/src/Test.jl:1577; macro expansion
   ╎    ╎    ╎    ╎    473 @UnicodePlots/test/tst_io.jl:69; macro expansion
   ╎    ╎    ╎    ╎     55  @Profile/src/Profile.jl:27; macro expansion
   ╎    ╎    ╎    ╎    ╎ 55  @UnicodePlots/src/show.jl:609; kwcall(::@NamedTuple{color::Bool}, ::typeof(string), p::Plot{HeatmapCanva
   ╎    ╎    ╎    ╎    ╎  55  @UnicodePlots/src/show.jl:611; string(p::Plot{HeatmapCanvas{typeof(identity), typeof(identity)}, Val{fa
   ╎    ╎    ╎    ╎    ╎   55  @UnicodePlots/src/show.jl:145; show
   ╎    ╎    ╎    ╎    ╎    1   @UnicodePlots/src/show.jl:269; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_c
   ╎    ╎    ╎    ╎    ╎     1   @Base/strings/basic.jl:765; ^
  1╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/strings/string.jl:526; repeat
   ╎    ╎    ╎    ╎    ╎    2   @UnicodePlots/src/show.jl:276; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_c
   ╎    ╎    ╎    ╎    ╎     2   @UnicodePlots/src/common.jl:540; no_ansi_escape
   ╎    ╎    ╎    ╎    ╎    ╎ 2   @Base/strings/util.jl:847; replace
   ╎    ╎    ╎    ╎    ╎    ╎  2   @Base/strings/util.jl:847; #replace#500
   ╎    ╎    ╎    ╎    ╎    ╎   2   @Base/strings/util.jl:788; _replace_(str::String, pat_repl::Tuple{Pair{Regex, String}}, count::In
   ╎    ╎    ╎    ╎    ╎    ╎    2   @Base/strings/util.jl:714; _replace_init(str::String, pat_repl::Tuple{Pair{Regex, String}}, coun
   ╎    ╎    ╎    ╎    ╎    ╎     2   @Base/tuple.jl:291; map
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 2   @Base/strings/util.jl:714; #493
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  2   @Base/regex.jl:588; _pat_replacer
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   2   @Base/regex.jl:583; RegexAndMatchData
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/pcre.jl:225; create_match_data
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/regex.jl:71; compile(regex::Regex)
   ╎    ╎    ╎    ╎    ╎    39  @UnicodePlots/src/show.jl:300; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_c
   ╎    ╎    ╎    ╎    ╎     39  ePlots/src/canvas/heatmapcanvas.jl:58; print_row(io::IOContext{IOBuffer}, ::Function, print_color::
   ╎    ╎    ╎    ╎    ╎    ╎ 39  @UnicodePlots/src/common.jl:498; print_color
   ╎    ╎    ╎    ╎    ╎    ╎  39  @UnicodePlots/src/common.jl:500; print_color(io::IOContext{IOBuffer}, color::UInt32, args::Char; b
   ╎    ╎    ╎    ╎    ╎    ╎   37  @UnicodePlots/src/common.jl:484; print_crayons(io::IOContext{IOBuffer}, c::Crayon, args::Char)
  2╎    ╎    ╎    ╎    ╎    ╎    36  @Crayons/src/crayon.jl:222; _print(io::IOContext{IOBuffer}, c::Crayon)
  1╎    ╎    ╎    ╎    ╎    ╎     1   @Base/strings/io.jl:44; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
  6╎    ╎    ╎    ╎    ╎    ╎     32  @Base/strings/io.jl:46; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 14  @Base/show.jl:1197; print(io::IOContext{IOBuffer}, n::UInt8)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  12  @Base/intfuncs.jl:881; string
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   12  @Base/intfuncs.jl:891; string(n::UInt8; base::Int64, pad::Int64)
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/intfuncs.jl:0; dec(x::UInt8, pad::Int64, neg::Bool)
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/intfuncs.jl:807; dec(x::UInt8, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    6   @Base/intfuncs.jl:809; dec(x::UInt8, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     6   @Base/iobuffer.jl:32; StringVector
  5╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 5   @Base/strings/string.jl:90; _string_n
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/strings/string.jl:100; unsafe_wrap
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    2   @Base/intfuncs.jl:810; dec(x::UInt8, pad::Int64, neg::Bool)
  1╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/intfuncs.jl:789; append_c_digits_fast(olength::Int64, digits::UInt8, buf::Vector{UIn
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/intfuncs.jl:802; append_c_digits_fast(olength::Int64, digits::UInt8, buf::Vector{UIn
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/intfuncs.jl:764; append_c_digits(olength::Int64, digits::UInt64, buf::Vector{UInt8}
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/div.jl:179; divrem
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/div.jl:201; divrem
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/div.jl:47; div
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/div.jl:343; div
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/int.jl:297; div
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    2   @Base/intfuncs.jl:812; dec(x::UInt8, pad::Int64, neg::Bool)
  2╎    ╎    ╎    ╎    ╎    ╎    ╎     2   @Base/strings/string.jl:67; String
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  2   @Base/strings/io.jl:250; print
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   2   @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    2   @Base/io.jl:431; unsafe_write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     2   @Base/iobuffer.jl:458; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 2   @Base/iobuffer.jl:342; ensureroom
  2╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  2   @Base/array.jl:1072; _growend!
  3╎    ╎    ╎    ╎    ╎    ╎    ╎ 3   @Base/strings/io.jl:34; print(io::IOContext{IOBuffer}, x::Int64)
  2╎    ╎    ╎    ╎    ╎    ╎    ╎ 8   @Base/strings/io.jl:35; print(io::IOContext{IOBuffer}, x::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  6   @Base/show.jl:1195; show
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   4   @Base/intfuncs.jl:881; string
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    3   @Base/intfuncs.jl:891; string(n::Int64; base::Int64, pad::Int64)
  1╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/intfuncs.jl:807; dec(x::UInt64, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/intfuncs.jl:808; dec(x::UInt64, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/intfuncs.jl:700; ndigits
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/intfuncs.jl:700; #ndigits#472
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/intfuncs.jl:661; ndigits0z
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/intfuncs.jl:603; ndigits0zpb(x::UInt64, b::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/intfuncs.jl:557; bit_ndigits0z
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/essentials.jl:13; getindex
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/intfuncs.jl:809; dec(x::UInt64, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/iobuffer.jl:32; StringVector
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/strings/string.jl:90; _string_n
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/intfuncs.jl:807; dec(x::UInt64, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   2   @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    2   @Base/io.jl:431; unsafe_write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     2   @Base/iobuffer.jl:458; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 2   @Base/iobuffer.jl:342; ensureroom
  2╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  2   @Base/array.jl:1072; _growend!
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/strings/io.jl:250; print(io::IOContext{IOBuffer}, s::String)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/io.jl:431; unsafe_write
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/iobuffer.jl:459; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
  1╎    ╎    ╎    ╎    ╎    ╎     1   @Base/strings/io.jl:47; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
  1╎    ╎    ╎    ╎    ╎    ╎    1   @Crayons/src/crayon.jl:226; _print(io::IOContext{IOBuffer}, c::Crayon)
   ╎    ╎    ╎    ╎    ╎    ╎   2   @UnicodePlots/src/common.jl:485; print_crayons(io::IOContext{IOBuffer}, c::Crayon, args::Char)
   ╎    ╎    ╎    ╎    ╎    ╎    2   @Base/strings/io.jl:46; print
   ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/char.jl:252; print(io::IOContext{IOBuffer}, c::Char)
  1╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/io.jl:752; write
   ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/strings/io.jl:250; print(io::IOContext{IOBuffer}, s::String)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/io.jl:431; unsafe_write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/iobuffer.jl:458; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/iobuffer.jl:342; ensureroom
  1╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/array.jl:1072; _growend!
   ╎    ╎    ╎    ╎    ╎    1   @UnicodePlots/src/show.jl:308; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_c
   ╎    ╎    ╎    ╎    ╎     1   @UnicodePlots/src/common.jl:495; print_color
   ╎    ╎    ╎    ╎    ╎    ╎ 1   @UnicodePlots/src/common.jl:498; print_color
   ╎    ╎    ╎    ╎    ╎    ╎  1   @UnicodePlots/src/common.jl:500; print_color(io::IOContext{IOBuffer}, color::UInt32, args::Char; b
   ╎    ╎    ╎    ╎    ╎    ╎   1   @UnicodePlots/src/common.jl:485; print_crayons(io::IOContext{IOBuffer}, c::Crayon, args::Char)
  1╎    ╎    ╎    ╎    ╎    ╎    1   @Base/strings/io.jl:46; print
   ╎    ╎    ╎    ╎    ╎    1   @UnicodePlots/src/show.jl:309; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_c
   ╎    ╎    ╎    ╎    ╎     1   @Base/strings/io.jl:250; print
   ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/io.jl:431; unsafe_write
   ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/iobuffer.jl:464; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
  1╎    ╎    ╎    ╎    ╎    ╎    1   @Base/array.jl:1021; setindex!
   ╎    ╎    ╎    ╎    ╎    8   @UnicodePlots/src/show.jl:316; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_c
   ╎    ╎    ╎    ╎    ╎     1   @UnicodePlots/src/show.jl:17; print_colorbar_row(io::IOContext{IOBuffer}, print_nocol::typeof(print)
  1╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/namedtuple.jl:171; getindex
   ╎    ╎    ╎    ╎    ╎     1   @UnicodePlots/src/show.jl:21; print_colorbar_row(io::IOContext{IOBuffer}, print_nocol::typeof(print)
   ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/strings/basic.jl:229; Symbol
   ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/boot.jl:516; Symbol(s::String)
  1╎    ╎    ╎    ╎    ╎    ╎   1   @Base/boot.jl:509; _Symbol
  1╎    ╎    ╎    ╎    ╎     4   @UnicodePlots/src/show.jl:33; print_colorbar_row(io::IOContext{IOBuffer}, print_nocol::typeof(print)
   ╎    ╎    ╎    ╎    ╎    ╎ 3   @UnicodePlots/src/common.jl:498; kwcall(::@NamedTuple{bgcol::UInt32}, ::typeof(UnicodePlots.print_c
   ╎    ╎    ╎    ╎    ╎    ╎  3   @UnicodePlots/src/common.jl:500; print_color(::IOContext{IOBuffer}, ::UInt32, ::Char, ::Vararg{Cha
   ╎    ╎    ╎    ╎    ╎    ╎   3   @UnicodePlots/src/common.jl:484; print_crayons(::IOContext{IOBuffer}, ::Crayon, ::Char, ::Vararg{
  1╎    ╎    ╎    ╎    ╎    ╎    1   @Crayons/src/crayon.jl:207; _print(io::IOContext{IOBuffer}, c::Crayon)
   ╎    ╎    ╎    ╎    ╎    ╎    2   @Crayons/src/crayon.jl:222; _print(io::IOContext{IOBuffer}, c::Crayon)
   ╎    ╎    ╎    ╎    ╎    ╎     2   @Base/strings/io.jl:46; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/show.jl:1197; print(io::IOContext{IOBuffer}, n::UInt8)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/intfuncs.jl:881; string
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/intfuncs.jl:891; string(n::UInt8; base::Int64, pad::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/intfuncs.jl:808; dec(x::UInt8, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/intfuncs.jl:700; ndigits
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/intfuncs.jl:700; #ndigits#472
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/intfuncs.jl:661; ndigits0z
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/intfuncs.jl:603; ndigits0zpb(x::UInt8, b::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/intfuncs.jl:556; bit_ndigits0z
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/int.jl:87; +
  1╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/strings/io.jl:34; print(io::IOContext{IOBuffer}, x::Int64)
   ╎    ╎    ╎    ╎    ╎     2   @UnicodePlots/src/show.jl:34; print_colorbar_row(io::IOContext{IOBuffer}, print_nocol::typeof(print)
   ╎    ╎    ╎    ╎    ╎    ╎ 2   @UnicodePlots/src/common.jl:495; print_color
   ╎    ╎    ╎    ╎    ╎    ╎  2   @UnicodePlots/src/common.jl:498; print_color
   ╎    ╎    ╎    ╎    ╎    ╎   2   @UnicodePlots/src/common.jl:500; print_color(io::IOContext{IOBuffer}, color::UInt32, args::Char; 
   ╎    ╎    ╎    ╎    ╎    ╎    1   @UnicodePlots/src/common.jl:484; print_crayons(io::IOContext{IOBuffer}, c::Crayon, args::Char)
   ╎    ╎    ╎    ╎    ╎    ╎     1   @Crayons/src/crayon.jl:221; _print(io::IOContext{IOBuffer}, c::Crayon)
  1╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/strings/io.jl:46; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
   ╎    ╎    ╎    ╎    ╎    ╎    1   @UnicodePlots/src/common.jl:485; print_crayons(io::IOContext{IOBuffer}, c::Crayon, args::Char)
  1╎    ╎    ╎    ╎    ╎    ╎     1   @Base/strings/io.jl:46; print
   ╎    ╎    ╎    ╎    ╎    1   @UnicodePlots/src/show.jl:335; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_c
   ╎    ╎    ╎    ╎    ╎     1   @UnicodePlots/src/show.jl:102; print_border
   ╎    ╎    ╎    ╎    ╎    ╎ 1   @UnicodePlots/src/show.jl:103; print_border(io::IOContext{IOBuffer}, print_nocol::typeof(print), pr
   ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/strings/basic.jl:229; Symbol
   ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/boot.jl:516; Symbol(s::String)
  1╎    ╎    ╎    ╎    ╎    ╎    1   @Base/boot.jl:509; _Symbol
   ╎    ╎    ╎    ╎    ╎    1   @UnicodePlots/src/show.jl:360; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_c
   ╎    ╎    ╎    ╎    ╎     1   @UnicodePlots/src/show.jl:122; print_labels(io::IOContext{IOBuffer}, print_nocol::typeof(print), pri
   ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/strings/basic.jl:229; Symbol
   ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/boot.jl:516; Symbol(s::String)
  1╎    ╎    ╎    ╎    ╎    ╎   1   @Base/boot.jl:509; _Symbol
   ╎    ╎    ╎    ╎    ╎    1   @UnicodePlots/src/show.jl:388; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_c
   ╎    ╎    ╎    ╎    ╎     1   @Base/strings/io.jl:250; print
   ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/io.jl:431; unsafe_write
   ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/iobuffer.jl:458; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
   ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/iobuffer.jl:342; ensureroom
  1╎    ╎    ╎    ╎    ╎    ╎     1   @Base/array.jl:1072; _growend!
406╎    ╎    ╎    ╎     418 @Profile/src/Profile.jl:29; macro expansion
   ╎    ╎    ╎    ╎    ╎ 11  @Base/compiler/typeinfer.jl:1078; typeinf_ext_toplevel(mi::Core.MethodInstance, world::UInt64)
   ╎    ╎    ╎    ╎    ╎  11  @Base/compiler/typeinfer.jl:1082; typeinf_ext_toplevel(interp::Core.Compiler.NativeInterpreter, linfo::
   ╎    ╎    ╎    ╎    ╎   1   @Base/compiler/typeinfer.jl:1048; typeinf_ext(interp::Core.Compiler.NativeInterpreter, mi::Core.Method
   ╎    ╎    ╎    ╎    ╎    1   @Base/compiler/types.jl:88; InferenceResult
   ╎    ╎    ╎    ╎    ╎     1   @Base/compiler/inferenceresult.jl:27; matching_cache_argtypes
   ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/compiler/inferenceresult.jl:109; most_general_argtypes
  1╎    ╎    ╎    ╎    ╎    ╎  1   @Base/compiler/inferenceresult.jl:111; most_general_argtypes(method::Method, specTypes::Any, withf
   ╎    ╎    ╎    ╎    ╎   2   @Base/compiler/typeinfer.jl:1049; typeinf_ext(interp::Core.Compiler.NativeInterpreter, mi::Core.Method
   ╎    ╎    ╎    ╎    ╎    1   @Base/compiler/inferencestate.jl:430; Core.Compiler.InferenceState(result::Core.Compiler.InferenceRes
  1╎    ╎    ╎    ╎    ╎     1   @Base/compiler/utilities.jl:143; retrieve_code_info
   ╎    ╎    ╎    ╎    ╎    1   @Base/compiler/inferencestate.jl:433; Core.Compiler.InferenceState(result::Core.Compiler.InferenceRes
   ╎    ╎    ╎    ╎    ╎     1   @Base/compiler/inferencestate.jl:292; Core.Compiler.InferenceState(result::Core.Compiler.InferenceRe
   ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/compiler/inferencestate.jl:406; should_insert_coverage(mod::Module, src::Core.CodeInfo)
  1╎    ╎    ╎    ╎    ╎    ╎  1   @Base/compiler/utilities.jl:503; coverage_enabled
   ╎    ╎    ╎    ╎    ╎   8   @Base/compiler/typeinfer.jl:1051; typeinf_ext(interp::Core.Compiler.NativeInterpreter, mi::Core.Method
  1╎    ╎    ╎    ╎    ╎    1   @Base/array.jl:0; typeinf(interp::Core.Compiler.NativeInterpreter, frame::Core.Compiler.InferenceStat
   ╎    ╎    ╎    ╎    ╎    7   @Base/compiler/typeinfer.jl:216; typeinf(interp::Core.Compiler.NativeInterpreter, frame::Core.Compile
   ╎    ╎    ╎    ╎    ╎     1   @Base/compiler/typeinfer.jl:260; _typeinf(interp::Core.Compiler.NativeInterpreter, frame::Core.Compi
   ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/compiler/typeinfer.jl:559; finish(me::Core.Compiler.InferenceState, interp::Core.Compiler.Nat
   ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/compiler/typeinfer.jl:715; type_annotate!(interp::Core.Compiler.NativeInterpreter, sv::Core.
   ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/array.jl:582; fill
   ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/array.jl:584; fill
   ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/boot.jl:486; Array
  1╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/boot.jl:477; Array
   ╎    ╎    ╎    ╎    ╎     5   @Base/compiler/typeinfer.jl:272; _typeinf(interp::Core.Compiler.NativeInterpreter, frame::Core.Compi
   ╎    ╎    ╎    ╎    ╎    ╎ 5   @Base/compiler/optimize.jl:453; optimize
   ╎    ╎    ╎    ╎    ╎    ╎  5   @Base/compiler/optimize.jl:504; run_passes
   ╎    ╎    ╎    ╎    ╎    ╎   5   @Base/compiler/optimize.jl:489; run_passes(ci::Core.CodeInfo, sv::Core.Compiler.OptimizationState
   ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/compiler/optimize.jl:623; slot2reg(ir::Core.Compiler.IRCode, ci::Core.CodeInfo, sv::Core.C
   ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/compiler/ssair/domtree.jl:229; construct_domtree(blocks::Vector{Core.Compiler.BasicBlock})
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/compiler/ssair/domtree.jl:239; update_domtree!
  1╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/compiler/ssair/domtree.jl:0; DFS!(D::Core.Compiler.DFSTree, blocks::Vector{Core.Compile
   ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/compiler/optimize.jl:626; slot2reg(ir::Core.Compiler.IRCode, ci::Core.CodeInfo, sv::Core.C
  1╎    ╎    ╎    ╎    ╎    ╎     1   @Base/array.jl:0; construct_ssa!(ci::Core.CodeInfo, ir::Core.Compiler.IRCode, domtree::Core.Com
   ╎    ╎    ╎    ╎    ╎    ╎    2   @Base/compiler/ssair/ir.jl:1855; compact!
   ╎    ╎    ╎    ╎    ╎    ╎     2   @Base/compiler/ssair/ir.jl:1855; compact!(code::Core.Compiler.IRCode, allow_cfg_transforms::Boo
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 2   @Base/compiler/ssair/ir.jl:673; IncrementalCompact
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/compiler/ssair/ir.jl:641; Core.Compiler.IncrementalCompact(code::Core.Compiler.IRCode, 
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/compiler/ssair/ir.jl:198; Core.Compiler.InstructionStream(len::Int64)
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/boot.jl:477; Array
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/compiler/ssair/ir.jl:643; Core.Compiler.IncrementalCompact(code::Core.Compiler.IRCode, 
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/boot.jl:496; Array
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/boot.jl:477; Array
   ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/compiler/ssair/passes.jl:1688; adce_pass!(ir::Core.Compiler.IRCode, inlining::Core.Compile
   ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/compiler/ssair/ir.jl:1592; iterate
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/compiler/ssair/ir.jl:1592; iterate
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/compiler/ssair/ir.jl:1670; iterate_compact(compact::Core.Compiler.IncrementalCompact)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/compiler/ssair/ir.jl:1343; process_node!(compact::Core.Compiler.IncrementalCompact, re
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/compiler/utilities.jl:75; quoted
  1╎    ╎    ╎    ╎    ╎    ╎    ╎     1   @Base/compiler/utilities.jl:70; is_self_quoting
   ╎    ╎    ╎    ╎    ╎     1   @Base/compiler/typeinfer.jl:283; _typeinf(interp::Core.Compiler.NativeInterpreter, frame::Core.Compi
   ╎    ╎    ╎    ╎    ╎    ╎ 1   @Base/compiler/typeinfer.jl:405; cache_result!(interp::Core.Compiler.NativeInterpreter, result::Cor
   ╎    ╎    ╎    ╎    ╎    ╎  1   @Base/compiler/typeinfer.jl:374; transform_result_for_cache
   ╎    ╎    ╎    ╎    ╎    ╎   1   @Base/compiler/optimize.jl:176; ir_to_codeinf!
   ╎    ╎    ╎    ╎    ╎    ╎    1   @Base/compiler/optimize.jl:184; ir_to_codeinf!
  1╎    ╎    ╎    ╎    ╎    ╎     1   @Base/compiler/optimize.jl:193; widen_all_consts!(src::Core.CodeInfo)
  1╎    ╎    ╎    ╎    ╎ 1   @Profile/src/Profile.jl:574; stop_timer()
  1╎1   @Crayons/src/crayon.jl:222; _print(io::IOContext{IOBuffer}, c::Crayon)
Total snapshots: 554. Utilization: 100% across all threads and tasks. Use the `groupby` kwarg to break down by thread and/or task.

And on 1.11.0-alpha2:

Overhead ╎ [+additional indent] Count File:Line; Function
=========================================================
   ╎872  @Base/client.jl:526; _start()
   ╎ 872  @Base/client.jl:291; exec_options(opts::Base.JLOptions)
   ╎  872  @Base/boot.jl:428; eval
   ╎   872  @Base/sysimg.jl:38; include(fname::String)
   ╎    872  @Base/loading.jl:2561; _include(mapexpr::Function, mod::Module, _path::String)
   ╎     872  @Base/loading.jl:2501; include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String)
   ╎    ╎ 872  @Base/boot.jl:428; eval
   ╎    ╎  872  @Base/env.jl:265; withenv(f::var"#1#2", keyvals::Pair{String, String})
   ╎    ╎   872  @UnicodePlots/test/runtests.jl:115; (::var"#1#2")()
   ╎    ╎    872  @TimerOutputs/src/TimerOutput.jl:237; macro expansion
   ╎    ╎     872  @UnicodePlots/test/runtests.jl:105; macro expansion
   ╎    ╎    ╎ 872  are/julia/stdlib/v1.11/Test/src/Test.jl:1700; macro expansion
   ╎    ╎    ╎  872  @UnicodePlots/test/runtests.jl:105; macro expansion
   ╎    ╎    ╎   872  @Base/sysimg.jl:38; include
   ╎    ╎    ╎    872  @Base/loading.jl:2561; _include(mapexpr::Function, mod::Module, _path::String)
   ╎    ╎    ╎     872  @Base/loading.jl:2501; include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String)
   ╎    ╎    ╎    ╎ 872  @Base/boot.jl:428; eval
   ╎    ╎    ╎    ╎  872  @UnicodePlots/test/tst_io.jl:60; top-level scope
   ╎    ╎    ╎    ╎   872  /julia/stdlib/v1.11/Test/src/Test.jl:1700; macro expansion
   ╎    ╎    ╎    ╎    872  @UnicodePlots/test/tst_io.jl:69; macro expansion
   ╎    ╎    ╎    ╎     137  /stdlib/v1.11/Profile/src/Profile.jl:59; macro expansion
   ╎    ╎    ╎    ╎    ╎ 137  @UnicodePlots/src/show.jl:609; kwcall(::@NamedTuple{color::Bool}, ::typeof(string), p::Plot{HeatmapCanv
   ╎    ╎    ╎    ╎    ╎  137  @UnicodePlots/src/show.jl:611; #string#107
   ╎    ╎    ╎    ╎    ╎   137  @UnicodePlots/src/show.jl:145; show
   ╎    ╎    ╎    ╎    ╎    1    @UnicodePlots/src/show.jl:276; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_
   ╎    ╎    ╎    ╎    ╎     1    @UnicodePlots/src/common.jl:540; no_ansi_escape
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/strings/util.jl:936; replace
   ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/strings/util.jl:936; #replace#585
   ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/strings/util.jl:877; _replace_(str::String, pat_repl::Tuple{Pair{Regex, String}}, count::I
   ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/strings/util.jl:803; _replace_init(str::String, pat_repl::Tuple{Pair{Regex, String}}, cou
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/tuple.jl:355; map
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/strings/util.jl:803; #578
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/regex.jl:619; _pat_replacer
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/regex.jl:614; RegexAndMatchData
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/pcre.jl:227; create_match_data
   ╎    ╎    ╎    ╎    ╎    2    @UnicodePlots/src/show.jl:298; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_
   ╎    ╎    ╎    ╎    ╎     2    @UnicodePlots/src/common.jl:495; print_color(io::IOContext{IOBuffer}, color::Symbol, args::Char)
   ╎    ╎    ╎    ╎    ╎    ╎ 2    @UnicodePlots/src/common.jl:498; print_color
   ╎    ╎    ╎    ╎    ╎    ╎  2    @UnicodePlots/src/common.jl:500; #print_color#13
   ╎    ╎    ╎    ╎    ╎    ╎   2    @UnicodePlots/src/common.jl:484; print_crayons(io::IOContext{IOBuffer}, c::Crayon, args::Char)
   ╎    ╎    ╎    ╎    ╎    ╎    2    @Crayons/src/crayon.jl:221; _print(io::IOContext{IOBuffer}, c::Crayon)
   ╎    ╎    ╎    ╎    ╎    ╎     2    @Base/strings/io.jl:46; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/show.jl:1254; print(io::IOContext{IOBuffer}, n::UInt8)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/intfuncs.jl:919; string
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/intfuncs.jl:929; string(n::UInt8; base::Int64, pad::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/intfuncs.jl:850; dec(x::UInt8, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/strings/string.jl:74; String
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/essentials.jl:11; length
  1╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/strings/io.jl:34; print(io::IOContext{IOBuffer}, x::Int64)
   ╎    ╎    ╎    ╎    ╎    108  @UnicodePlots/src/show.jl:300; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_
   ╎    ╎    ╎    ╎    ╎     1    ePlots/src/canvas/heatmapcanvas.jl:57; print_row(io::IOContext{IOBuffer}, ::Function, print_color:
   ╎    ╎    ╎    ╎    ╎    ╎ 1    .11/LinearAlgebra/src/adjtrans.jl:334; getindex
   ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/array.jl:919; getindex
   ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/abstractarray.jl:1371; _to_linear_index
   ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/abstractarray.jl:3068; _sub2ind
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/abstractarray.jl:3084; _sub2ind
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/abstractarray.jl:3100; _sub2ind_recurse
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/abstractarray.jl:3100; _sub2ind_recurse
  1╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/int.jl:88; *
 16╎    ╎    ╎    ╎    ╎     107  ePlots/src/canvas/heatmapcanvas.jl:58; print_row(io::IOContext{IOBuffer}, ::Function, print_color:
  7╎    ╎    ╎    ╎    ╎    ╎ 7    @Base/boot.jl:725; NamedTuple
  8╎    ╎    ╎    ╎    ╎    ╎ 84   @UnicodePlots/src/common.jl:498; kwcall(::@NamedTuple{bgcol::UInt32}, ::typeof(UnicodePlots.print_
  2╎    ╎    ╎    ╎    ╎    ╎  2    @UnicodePlots/src/common.jl:498; print_color(::IOContext{IOBuffer}, ::UInt32, ::Char, ::Vararg{Ch
  1╎    ╎    ╎    ╎    ╎    ╎  1    @UnicodePlots/src/common.jl:499; print_color(::IOContext{IOBuffer}, ::UInt32, ::Char, ::Vararg{Ch
  6╎    ╎    ╎    ╎    ╎    ╎  73   @UnicodePlots/src/common.jl:500; print_color(::IOContext{IOBuffer}, ::UInt32, ::Char, ::Vararg{Ch
  2╎    ╎    ╎    ╎    ╎    ╎   2    @UnicodePlots/src/common.jl:480; print_crayons(::IOContext{IOBuffer}, ::Crayon, ::Char, ::Vararg
   ╎    ╎    ╎    ╎    ╎    ╎   1    @UnicodePlots/src/common.jl:483; print_crayons(::IOContext{IOBuffer}, ::Crayon, ::Char, ::Vararg
   ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/strings/io.jl:250; print
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/io.jl:452; unsafe_write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/iobuffer.jl:519; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
  1╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/int.jl:87; +
   ╎    ╎    ╎    ╎    ╎    ╎   43   @UnicodePlots/src/common.jl:484; print_crayons(::IOContext{IOBuffer}, ::Crayon, ::Char, ::Vararg
  1╎    ╎    ╎    ╎    ╎    ╎    41   @Crayons/src/crayon.jl:222; _print(io::IOContext{IOBuffer}, c::Crayon)
  1╎    ╎    ╎    ╎    ╎    ╎     1    @Base/strings/io.jl:44; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
 14╎    ╎    ╎    ╎    ╎    ╎     39   @Base/strings/io.jl:46; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 15   @Base/show.jl:1254; print(io::IOContext{IOBuffer}, n::UInt8)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  11   @Base/intfuncs.jl:919; string
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   11   @Base/intfuncs.jl:929; string(n::UInt8; base::Int64, pad::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    2    @Base/intfuncs.jl:846; dec(x::UInt8, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     2    @Base/intfuncs.jl:738; ndigits
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 2    @Base/intfuncs.jl:738; #ndigits#523
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  2    @Base/intfuncs.jl:699; ndigits0z
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/intfuncs.jl:0; ndigits0zpb(x::UInt8, b::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/intfuncs.jl:641; ndigits0zpb(x::UInt8, b::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/intfuncs.jl:595; bit_ndigits0z
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/int.jl:1013; -
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/int.jl:86; -
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    5    @Base/intfuncs.jl:847; dec(x::UInt8, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     5    @Base/iobuffer.jl:45; StringVector
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/array.jl:3113; wrap
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 4    @Base/iobuffer.jl:44; StringMemory
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/strings/string.jl:109; _string_n
  3╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  3    @Base/strings/string.jl:119; unsafe_wrap
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    2    @Base/intfuncs.jl:848; dec(x::UInt8, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     2    @Base/intfuncs.jl:840; append_c_digits_fast(olength::Int64, digits::UInt8, buf::Vector{UI
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/intfuncs.jl:801; append_c_digits(olength::Int64, digits::UInt64, buf::Vector{UInt8
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/intfuncs.jl:805; append_c_digits(olength::Int64, digits::UInt64, buf::Vector{UInt8
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/int.jl:87; +
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    2    @Base/intfuncs.jl:850; dec(x::UInt8, pad::Int64, neg::Bool)
  2╎    ╎    ╎    ╎    ╎    ╎    ╎     2    @Base/strings/string.jl:78; String
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  4    @Base/strings/io.jl:250; print
  1╎    ╎    ╎    ╎    ╎    ╎    ╎   4    @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    3    @Base/io.jl:452; unsafe_write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     3    @Base/iobuffer.jl:512; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/iobuffer.jl:385; ensureroom
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/Base.jl:49; getproperty
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 2    @Base/iobuffer.jl:391; ensureroom
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  2    @Base/iobuffer.jl:307; _resize!(io::IOBuffer, sz::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   2    @Base/iobuffer.jl:156; _similar_data
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    2    @Base/iobuffer.jl:44; StringMemory
  2╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     2    @Base/strings/string.jl:109; _string_n
  1╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/strings/io.jl:34; print(io::IOContext{IOBuffer}, x::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 6    @Base/strings/io.jl:35; print(io::IOContext{IOBuffer}, x::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  6    @Base/show.jl:1252; show
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   5    @Base/intfuncs.jl:919; string
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    5    @Base/intfuncs.jl:929; string(n::Int64; base::Int64, pad::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     2    @Base/intfuncs.jl:846; dec(x::UInt64, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 2    @Base/intfuncs.jl:738; ndigits
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  2    @Base/intfuncs.jl:738; #ndigits#523
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   2    @Base/intfuncs.jl:699; ndigits0z
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/intfuncs.jl:633; ndigits0zpb(x::UInt64, b::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/int.jl:518; ==
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/promotion.jl:635; ==
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/intfuncs.jl:641; ndigits0zpb(x::UInt64, b::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/intfuncs.jl:595; bit_ndigits0z
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/essentials.jl:892; getindex
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/intfuncs.jl:847; dec(x::UInt64, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/iobuffer.jl:45; StringVector
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/iobuffer.jl:44; StringMemory
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/strings/string.jl:109; _string_n
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/intfuncs.jl:848; dec(x::UInt64, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/intfuncs.jl:840; append_c_digits_fast(olength::Int64, digits::UInt64, buf::Vector{
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/intfuncs.jl:805; append_c_digits(olength::Int64, digits::UInt64, buf::Vector{UInt
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/int.jl:87; +
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/intfuncs.jl:850; dec(x::UInt64, pad::Int64, neg::Bool)
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/strings/string.jl:78; String
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/io.jl:452; unsafe_write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/iobuffer.jl:512; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/iobuffer.jl:389; ensureroom
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/Base.jl:49; getproperty
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 3    @Base/strings/io.jl:250; print(io::IOContext{IOBuffer}, s::String)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  3    @Base/strings/io.jl:248; write
  1╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/Base.jl:296; sizeof
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   2    @Base/io.jl:452; unsafe_write
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/iobuffer.jl:511; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/iobuffer.jl:517; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
  2╎    ╎    ╎    ╎    ╎    ╎    2    @Crayons/src/crayon.jl:226; _print(io::IOContext{IOBuffer}, c::Crayon)
 17╎    ╎    ╎    ╎    ╎    ╎   21   @UnicodePlots/src/common.jl:485; print_crayons(::IOContext{IOBuffer}, ::Crayon, ::Char, ::Vararg
  1╎    ╎    ╎    ╎    ╎    ╎    3    @Base/strings/io.jl:46; print(::IOContext{IOBuffer}, ::String, ::Char, ::Vararg{Any})
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/char.jl:252; print(io::IOContext{IOBuffer}, c::Char)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/io.jl:869; write(io::IOContext{IOBuffer}, c::Char)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/io.jl:450; write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/iobuffer.jl:531; write
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/iobuffer.jl:385; ensureroom
  1╎    ╎    ╎    ╎    ╎    ╎     1    @Base/io.jl:865; write(io::IOContext{IOBuffer}, c::Char)
   ╎    ╎    ╎    ╎    ╎    1    @UnicodePlots/src/show.jl:308; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_
  1╎    ╎    ╎    ╎    ╎     1    @UnicodePlots/src/common.jl:495; print_color(io::IOContext{IOBuffer}, color::Symbol, args::Char)
   ╎    ╎    ╎    ╎    ╎    20   @UnicodePlots/src/show.jl:316; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_
   ╎    ╎    ╎    ╎    ╎     3    @UnicodePlots/src/show.jl:21; print_colorbar_row(io::IOContext{IOBuffer}, print_nocol::typeof(print
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/strings/basic.jl:229; Symbol
  1╎    ╎    ╎    ╎    ╎    ╎  1    @Base/strings/substring.jl:236; string
   ╎    ╎    ╎    ╎    ╎    ╎ 2    @UnicodePlots/src/common.jl:495; print_color(::IOContext{IOBuffer}, ::Symbol, ::Char, ::Vararg{Cha
   ╎    ╎    ╎    ╎    ╎    ╎  2    @UnicodePlots/src/common.jl:498; print_color(::IOContext{IOBuffer}, ::UInt32, ::Char, ::Vararg{An
   ╎    ╎    ╎    ╎    ╎    ╎   2    @UnicodePlots/src/common.jl:500; print_color(::IOContext{IOBuffer}, ::UInt32, ::Char, ::Vararg{A
  2╎    ╎    ╎    ╎    ╎    ╎    2    @UnicodePlots/src/common.jl:485; print_crayons(::IOContext{IOBuffer}, ::Crayon, ::Char, ::Varar
  1╎    ╎    ╎    ╎    ╎     2    @UnicodePlots/src/show.jl:30; print_colorbar_row(io::IOContext{IOBuffer}, print_nocol::typeof(print
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @UnicodePlots/src/common.jl:612; (::UnicodePlots.var"#16#17"{ColorSchemes.ColorScheme{Vector{RGB{F
   ╎    ╎    ╎    ╎    ╎    ╎  1    @ColorSchemes/src/ColorSchemes.jl:302; get
   ╎    ╎    ╎    ╎    ╎    ╎   1    @ColorSchemes/src/ColorSchemes.jl:305; get
   ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/number.jl:284; map
   ╎    ╎    ╎    ╎    ╎    ╎     1    olorSchemes/src/ColorSchemes.jl:312; (::ColorSchemes.var"#2#3"{ColorSchemes.ColorScheme{Vecto
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    olorSchemes/src/ColorSchemes.jl:299; fast_weighted_color_mean
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/promotion.jl:427; -
  1╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/float.jl:479; -
  2╎    ╎    ╎    ╎    ╎     14   @UnicodePlots/src/show.jl:33; print_colorbar_row(io::IOContext{IOBuffer}, print_nocol::typeof(print
  1╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/boot.jl:725; NamedTuple
  1╎    ╎    ╎    ╎    ╎    ╎ 11   @UnicodePlots/src/common.jl:498; kwcall(::@NamedTuple{bgcol::UInt32}, ::typeof(UnicodePlots.print_
   ╎    ╎    ╎    ╎    ╎    ╎  10   @UnicodePlots/src/common.jl:500; print_color(::IOContext{IOBuffer}, ::UInt32, ::Char, ::Vararg{Ch
   ╎    ╎    ╎    ╎    ╎    ╎   7    @UnicodePlots/src/common.jl:484; print_crayons(::IOContext{IOBuffer}, ::Crayon, ::Char, ::Vararg
  1╎    ╎    ╎    ╎    ╎    ╎    7    @Crayons/src/crayon.jl:222; _print(io::IOContext{IOBuffer}, c::Crayon)
   ╎    ╎    ╎    ╎    ╎    ╎     6    @Base/strings/io.jl:46; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
  1╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/iobuffer.jl:511; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 3    @Base/show.jl:1254; print(io::IOContext{IOBuffer}, n::UInt8)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  3    @Base/intfuncs.jl:919; string
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   3    @Base/intfuncs.jl:929; string(n::UInt8; base::Int64, pad::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/intfuncs.jl:847; dec(x::UInt8, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/iobuffer.jl:45; StringVector
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/array.jl:3114; wrap
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/intfuncs.jl:848; dec(x::UInt8, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/intfuncs.jl:840; append_c_digits_fast(olength::Int64, digits::UInt8, buf::Vector{UI
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/int.jl:551; rem
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/number.jl:7; convert
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/boot.jl:895; UInt64
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/boot.jl:867; toUInt64
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/intfuncs.jl:850; dec(x::UInt8, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/strings/string.jl:84; String
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/boot.jl:518; GenericMemory
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/boot.jl:512; GenericMemory
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 2    @Base/strings/io.jl:35; print(io::IOContext{IOBuffer}, x::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  2    @Base/show.jl:1252; show
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   2    @Base/intfuncs.jl:919; string
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    2    @Base/intfuncs.jl:929; string(n::Int64; base::Int64, pad::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/intfuncs.jl:846; dec(x::UInt64, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/intfuncs.jl:738; ndigits
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/intfuncs.jl:738; #ndigits#523
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/intfuncs.jl:699; ndigits0z
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/intfuncs.jl:641; ndigits0zpb(x::UInt64, b::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/intfuncs.jl:595; bit_ndigits0z
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/essentials.jl:892; getindex
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/intfuncs.jl:847; dec(x::UInt64, pad::Int64, neg::Bool)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/iobuffer.jl:45; StringVector
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/iobuffer.jl:44; StringMemory
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/strings/string.jl:109; _string_n
  1╎    ╎    ╎    ╎    ╎    ╎   3    @UnicodePlots/src/common.jl:485; print_crayons(::IOContext{IOBuffer}, ::Crayon, ::Char, ::Vararg
  2╎    ╎    ╎    ╎    ╎    ╎    2    @Base/strings/io.jl:46; print(::IOContext{IOBuffer}, ::String, ::Char, ::Vararg{Any})
   ╎    ╎    ╎    ╎    ╎     1    @UnicodePlots/src/show.jl:39; print_colorbar_row(io::IOContext{IOBuffer}, print_nocol::typeof(print
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/strings/basic.jl:265; *
  1╎    ╎    ╎    ╎    ╎    ╎  1    @Base/strings/substring.jl:236; string
   ╎    ╎    ╎    ╎    ╎    2    @UnicodePlots/src/show.jl:335; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_
   ╎    ╎    ╎    ╎    ╎     2    @UnicodePlots/src/show.jl:102; print_border
   ╎    ╎    ╎    ╎    ╎    ╎ 2    @UnicodePlots/src/show.jl:103; print_border(io::IOContext{IOBuffer}, print_nocol::typeof(print), p
   ╎    ╎    ╎    ╎    ╎    ╎  2    @UnicodePlots/src/common.jl:495; print_color(::IOContext{IOBuffer}, ::Symbol, ::Char, ::Vararg{An
   ╎    ╎    ╎    ╎    ╎    ╎   2    @UnicodePlots/src/common.jl:498; print_color(::IOContext{IOBuffer}, ::UInt32, ::Char, ::Vararg{A
   ╎    ╎    ╎    ╎    ╎    ╎    2    @UnicodePlots/src/common.jl:500; print_color(::IOContext{IOBuffer}, ::UInt32, ::Char, ::Vararg{
  2╎    ╎    ╎    ╎    ╎    ╎     2    @UnicodePlots/src/common.jl:485; print_crayons(::IOContext{IOBuffer}, ::Crayon, ::Char, ::Vara
   ╎    ╎    ╎    ╎    ╎    2    @UnicodePlots/src/show.jl:360; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_
   ╎    ╎    ╎    ╎    ╎     1    @UnicodePlots/src/show.jl:134; print_labels(io::IOContext{IOBuffer}, print_nocol::typeof(print), pr
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @UnicodePlots/src/common.jl:498; print_color
   ╎    ╎    ╎    ╎    ╎    ╎  1    @UnicodePlots/src/common.jl:500; #print_color#13
   ╎    ╎    ╎    ╎    ╎    ╎   1    @UnicodePlots/src/common.jl:484; print_crayons(io::IOContext{IOBuffer}, c::Crayon, args::String)
   ╎    ╎    ╎    ╎    ╎    ╎    1    @Crayons/src/crayon.jl:221; _print(io::IOContext{IOBuffer}, c::Crayon)
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/strings/io.jl:46; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/strings/io.jl:35; print(io::IOContext{IOBuffer}, x::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/show.jl:1252; show
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/io.jl:452; unsafe_write
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/iobuffer.jl:517; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/operators.jl:379; >
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/int.jl:83; <
   ╎    ╎    ╎    ╎    ╎     1    @UnicodePlots/src/show.jl:135; print_labels(io::IOContext{IOBuffer}, print_nocol::typeof(print), pr
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/int.jl:97; /
   ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/float.jl:374; float
   ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/float.jl:348; AbstractFloat
  1╎    ╎    ╎    ╎    ╎    ╎    1    @Base/float.jl:239; Float64
   ╎    ╎    ╎    ╎    ╎    1    @UnicodePlots/src/show.jl:388; _show(end_io::IOContext{IOBuffer}, print_nocol::typeof(print), print_
   ╎    ╎    ╎    ╎    ╎     1    @Base/strings/io.jl:250; print
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/strings/io.jl:248; write
   ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/io.jl:452; unsafe_write
   ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/iobuffer.jl:518; unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
  1╎    ╎    ╎    ╎    ╎    ╎    1    @Base/genericmemory.jl:213; setindex!
718╎    ╎    ╎    ╎     735  /stdlib/v1.11/Profile/src/Profile.jl:61; macro expansion
   ╎    ╎    ╎    ╎    ╎ 16   @Base/compiler/typeinfer.jl:1079; typeinf_ext_toplevel(mi::Core.MethodInstance, world::UInt64)
   ╎    ╎    ╎    ╎    ╎  16   @Base/compiler/typeinfer.jl:1083; typeinf_ext_toplevel(interp::Core.Compiler.NativeInterpreter, mi::Co
   ╎    ╎    ╎    ╎    ╎   1    @Base/compiler/typeinfer.jl:1042; typeinf_ext(interp::Core.Compiler.NativeInterpreter, mi::Core.Metho
   ╎    ╎    ╎    ╎    ╎    1    @Base/compiler/types.jl:99; InferenceResult
   ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/inferenceresult.jl:27; matching_cache_argtypes(𝕃::Core.Compiler.InferenceLattice{Cor
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/compiler/inferenceresult.jl:115; most_general_argtypes
  1╎    ╎    ╎    ╎    ╎    ╎  1    @Base/compiler/inferenceresult.jl:117; most_general_argtypes(method::Method, specTypes::Any, with
   ╎    ╎    ╎    ╎    ╎   2    @Base/compiler/typeinfer.jl:1043; typeinf_ext(interp::Core.Compiler.NativeInterpreter, mi::Core.Metho
   ╎    ╎    ╎    ╎    ╎    2    @Base/compiler/inferencestate.jl:499; InferenceState
   ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/inferencestate.jl:494; Core.Compiler.InferenceState(result::Core.Compiler.InferenceR
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/compiler/utilities.jl:143; retrieve_code_info
  1╎    ╎    ╎    ╎    ╎    ╎  1    @Base/reflection.jl:1320; _uncompressed_ir
   ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/inferencestate.jl:497; Core.Compiler.InferenceState(result::Core.Compiler.InferenceR
  1╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/bitset.jl:36; union!(s::Core.Compiler.BitSet, itr::Int64)
   ╎    ╎    ╎    ╎    ╎   13   @Base/compiler/typeinfer.jl:1045; typeinf_ext(interp::Core.Compiler.NativeInterpreter, mi::Core.Metho
   ╎    ╎    ╎    ╎    ╎    13   @Base/compiler/typeinfer.jl:216; typeinf(interp::Core.Compiler.NativeInterpreter, frame::Core.Compil
  1╎    ╎    ╎    ╎    ╎     1    ompiler/abstractinterpretation.jl:3384; typeinf_nocycle(interp::Core.Compiler.NativeInterpreter, f
   ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/typeinfer.jl:246; _typeinf(interp::Core.Compiler.NativeInterpreter, frame::Core.Comp
   ╎    ╎    ╎    ╎    ╎    ╎ 1    ompiler/abstractinterpretation.jl:3385; typeinf_nocycle(interp::Core.Compiler.NativeInterpreter, 
  1╎    ╎    ╎    ╎    ╎    ╎  1    mpiler/abstractinterpretation.jl:3074; update_bestguess!(interp::Core.Compiler.NativeInterpreter
  1╎    ╎    ╎    ╎    ╎     8    @Base/compiler/typeinfer.jl:264; _typeinf(interp::Core.Compiler.NativeInterpreter, frame::Core.Comp
   ╎    ╎    ╎    ╎    ╎    ╎ 6    @Base/compiler/optimize.jl:957; optimize(interp::Core.Compiler.NativeInterpreter, opt::Core.Compil
   ╎    ╎    ╎    ╎    ╎    ╎  6    @Base/compiler/optimize.jl:983; run_passes_ipo_safe
   ╎    ╎    ╎    ╎    ╎    ╎   6    @Base/compiler/optimize.jl:968; run_passes_ipo_safe(ci::Core.CodeInfo, sv::Core.Compiler.Optimiz
   ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/compiler/optimize.jl:1190; slot2reg(ir::Core.Compiler.IRCode, ci::Core.CodeInfo, sv::Core
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/ssair/ir.jl:400; construct_domtree
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/compiler/ssair/ir.jl:401; construct_domtree
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/compiler/ssair/domtree.jl:242; construct_domtree
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/compiler/ssair/domtree.jl:252; update_domtree!
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/compiler/ssair/domtree.jl:124; DFS!(D::Core.Compiler.DFSTree, blocks::Vector{Core.Co
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    ase/compiler/ssair/domtree.jl:115; resize!
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/array.jl:1436; resize!(a::Vector{Int64}, nl::Int64)
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/array.jl:1100; _growend!
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/array.jl:1113; (::Core.Compiler.var"#132#133"{Vector{Int64}, Int64, Int64, Int64
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/array.jl:1047; array_new_memory
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/boot.jl:514; GenericMemory
   ╎    ╎    ╎    ╎    ╎    ╎    2    @Base/compiler/optimize.jl:1193; slot2reg(ir::Core.Compiler.IRCode, ci::Core.CodeInfo, sv::Core
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/ssair/slot2ssa.jl:574; construct_ssa!(ci::Core.CodeInfo, ir::Core.Compiler.IRCo
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/array.jl:389; getindex
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/boot.jl:576; Array
  1╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/boot.jl:512; GenericMemory
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/ssair/slot2ssa.jl:864; construct_ssa!(ci::Core.CodeInfo, ir::Core.Compiler.IRCo
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/boot.jl:576; Array
  1╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/boot.jl:514; GenericMemory
   ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/compiler/ssair/inlining.jl:78; ssa_inlining_pass!
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/ssair/inlining.jl:1640; assemble_inline_todo!(ir::Core.Compiler.IRCode, state::
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/compiler/ssair/inlining.jl:1264; process_simple!(todo::Vector{Pair{Int64, Any}}, ir::Co
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    ase/compiler/ssair/inlining.jl:1234; add_inst_flag!
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    ase/compiler/ssair/inlining.jl:1237; add_inst_flag!
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/compiler/optimize.jl:383; recompute_effects_flags
  1╎    ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/optimize.jl:0; stmt_effect_flags(𝕃ₒ::Core.Compiler.PartialsLattice{Core.Co
   ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/compiler/ssair/ir.jl:2001; compact!
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/ssair/ir.jl:2003; compact!(code::Core.Compiler.IRCode, allow_cfg_transforms::Bo
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/compiler/ssair/ir.jl:1731; iterate
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/compiler/ssair/ir.jl:1731; iterate
  1╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/compiler/ssair/ir.jl:1352; process_node!(compact::Core.Compiler.IncrementalCompact, r
   ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/compiler/ssair/passes.jl:2015; adce_pass!(ir::Core.Compiler.IRCode, inlining::Core.Compil
   ╎    ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/ssair/ir.jl:724; IncrementalCompact
   ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/compiler/ssair/ir.jl:625; CFGTransformState!(blocks::Vector{Core.Compiler.BasicBlock}, 
   ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/compiler/ssair/domtree.jl:242; construct_domtree
   ╎    ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/compiler/ssair/domtree.jl:260; update_domtree!
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    1    @Base/compiler/ssair/domtree.jl:280; compute_domtree_nodes!(domtree::Core.Compiler.Generic
   ╎    ╎    ╎    ╎    ╎    ╎    ╎     1    ase/compiler/ssair/domtree.jl:288; update_level!(nodes::Vector{Core.Compiler.DomTreeNode
   ╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/array.jl:1569; pop!
  1╎    ╎    ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/essentials.jl:892; getindex
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/compiler/optimize.jl:958; optimize(interp::Core.Compiler.NativeInterpreter, opt::Core.Compil
   ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/compiler/optimize.jl:934; ipo_dataflow_analysis!(interp::Core.Compiler.NativeInterpreter, i
   ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/compiler/ssair/irinterp.jl:244; scan!(callback::Core.Compiler.ScanStmt, scanner::Core.Comp
  1╎    ╎    ╎    ╎    ╎    ╎    1    @Base/essentials.jl:892; getindex
   ╎    ╎    ╎    ╎    ╎     1    @Base/compiler/typeinfer.jl:268; _typeinf(interp::Core.Compiler.NativeInterpreter, frame::Core.Comp
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/compiler/typeinfer.jl:231; finish!(interp::Core.Compiler.NativeInterpreter, caller::Core.Com
   ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/compiler/optimize.jl:216; ir_to_codeinf!
   ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/compiler/optimize.jl:223; ir_to_codeinf!
  1╎    ╎    ╎    ╎    ╎    ╎    1    @Base/compiler/ssair/legacy.jl:71; replace_code_newstyle!(ci::Core.CodeInfo, ir::Core.Compiler.
   ╎    ╎    ╎    ╎    ╎     2    @Base/compiler/typeinfer.jl:270; _typeinf(interp::Core.Compiler.NativeInterpreter, frame::Core.Comp
   ╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/compiler/typeinfer.jl:391; cache_result!(interp::Core.Compiler.NativeInterpreter, result::Co
   ╎    ╎    ╎    ╎    ╎    ╎  1    @Base/compiler/typeinfer.jl:319; Core.CodeInstance(interp::Core.Compiler.NativeInterpreter, resul
   ╎    ╎    ╎    ╎    ╎    ╎   1    @Base/compiler/typeinfer.jl:364; transform_result_for_cache
  1╎    ╎    ╎    ╎    ╎    ╎    1    @Base/compiler/typeinfer.jl:350; maybe_compress_codeinfo(interp::Core.Compiler.NativeInterprete
  1╎    ╎    ╎    ╎    ╎    ╎ 1    @Base/compiler/typeinfer.jl:392; cache_result!(interp::Core.Compiler.NativeInterpreter, result::Co
  1╎    ╎    ╎    ╎    ╎ 1    stdlib/v1.11/Profile/src/Profile.jl:606; stop_timer()
  2╎2    @Base/strings/io.jl:46; print(::IOContext{IOBuffer}, ::Int64, ::String, ::Vararg{Any})
Total snapshots: 1022. Utilization: 100% across all threads and tasks. Use the `groupby` kwarg to break down by thread and/or task.

@IanButterworth
Copy link
Member

IanButterworth commented Mar 20, 2024

Thanks. Can you try with and without coverage on? (It looks like it's currently on in the above cases?)

@KristofferC
Copy link
Member

KristofferC commented Mar 20, 2024

If I put

using UnicodePlots, Test 
using BenchmarkTools
p = heatmap(collect(1:30) * collect(1:30)')
@btime string(p; color = true) 

in runtests.jl I cannot observe a difference if I run with Pkg.test or including it. Did you manage to repro it at all locally?

(UnicodePlots) pkg> test
     Testing UnicodePlots
      Status `/tmp/jl_GnheYo/Project.toml`
  [4c88cf16] Aqua v0.8.4
  [6e4b80f9] BenchmarkTools v1.5.0
...
  [3f19e933] p7zip_jll v17.4.0+2
        Info Packages marked with ⌃ and ⌅ have new versions available. Those with ⌃ may be upgradable, but those with ⌅ are restricted by compatibility constraints from upgrading.
     Testing Running tests...
  218.893 μs (11194 allocations: 364.15 KiB)
     Testing UnicodePlots tests passed

julia> include("test/runtests.jl")
  208.180 μs (11194 allocations: 364.15 KiB)

@t-bltg
Copy link
Contributor Author

t-bltg commented Mar 20, 2024

Are you on 1.11.0-alpha2 ?

(UnicodePlots) pkg> test fails locally

This also fails locally:

using TestEnv
TestEnv.activate()
include("test/runtests.jl")

@IanButterworth
Copy link
Member

IanButterworth commented Mar 20, 2024

Given coverage is on on CI, I tried moving the load of UnicodePlots last in case it was due to #53457

but it still fails JuliaPlots/UnicodePlots.jl#375

So doesn't seem to be due to that coverage issue.

And you're reporting it locally without coverage turned on, I believe

@t-bltg
Copy link
Contributor Author

t-bltg commented Mar 20, 2024

@IanButterworth, thanks for trying this !

@KristofferC
Copy link
Member

(UnicodePlots) pkg> test fails locally

Ok, but I am asking for something smaller that shows the test case in #53688 (comment) being slower.

@t-bltg
Copy link
Contributor Author

t-bltg commented Mar 20, 2024

And you're reporting it locally without coverage turned on, I believe

I've tested:

using TestEnv
TestEnv.activate()
include("test/runtests.jl")

with --code-coverage and with --code-coverage=none, and this doesn't make a difference.

@t-bltg t-bltg changed the title Test performance regression in UnicodePlots with julia 1.11.0-alpha1 Test performance regression in UnicodePlots with julia 1.11.0-alpha2 Mar 26, 2024
@t-bltg
Copy link
Contributor Author

t-bltg commented Mar 26, 2024

Oddly, when I move the definition of the function sombrero outside the @testset block, the regression disappears.

So this appears to be a Test module issue / regression, anyway I have a workaround now.

@KristofferC
Copy link
Member

That's a useful observation. It shouldn't be too hard to bisect it from that.

@IanButterworth
Copy link
Member

IanButterworth commented Mar 28, 2024

I tried testing this locally on nightly and didn't see the test failure.
That was with e07c0f1 and UnicodePlots v3.6.4 (before the fix) and FedeClaudi/Term.jl#245 which was required due to #53704 (maybe that type stability fix helped?)

@t-bltg
Copy link
Contributor Author

t-bltg commented Mar 28, 2024

Thanks @IanButterworth , I'll try to bisect on 1.11 next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants