From 59b92a87458ed44f466792b60b125e6479017cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4cker?= Date: Sat, 10 Oct 2026 08:47:46 +0200 Subject: [PATCH 1/3] Precompile the display of `N0f8` and `N0f16` Showing a value or a vector for the first time was the slowest first use of the package. Precompiling `show` and `print` for the terminal and for buffers cuts the first display in the terminal from 302 to 82 ms on Julia 1.10 and from 913 to 88 ms on Julia 1.13, and the first `repr` from 438 to 113 ms and from 553 to 107 ms. Loading becomes 8 ms (1.10) and 2 ms (1.13) slower, and the package image grows by about 1 MiB. Invalidations do not change, neither from loading the package nor from loading ColorTypes and Colors afterwards. --- src/precompile.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/precompile.jl b/src/precompile.jl index 83810a7..359217f 100644 --- a/src/precompile.jl +++ b/src/precompile.jl @@ -29,5 +29,12 @@ function _precompile_() precompile(Tuple{typeof(convert),Type{T},S}) precompile(Tuple{typeof(convert),Type{S},T}) end + # display in the terminal and into buffers (e.g. `repr`) + for IOT in (IOContext{Base.TTY}, IOContext{IOBuffer}, IOBuffer) + precompile(Tuple{typeof(show),IOT,T}) + precompile(Tuple{typeof(print),IOT,T}) + precompile(Tuple{typeof(show),IOT,MIME"text/plain",T}) + precompile(Tuple{typeof(show),IOT,MIME"text/plain",Vector{T}}) + end end end From 475c1336d8f8920478f6f7d8df0384bf78606a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4cker?= Date: Fri, 16 Oct 2026 09:30:05 +0200 Subject: [PATCH 2/3] Precompile the display of `N0f8` and `N0f16` into pipes Scripts whose output is piped, such as CI jobs and TTFX benchmarks, print through `IOContext{Base.PipeEndpoint}`. Without these directives, the first display of an `RGB{N0f8}` vector takes about 2 s on Julia 1.13 and 1.4 s on 1.10, with them about 0.4 s. --- src/precompile.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/precompile.jl b/src/precompile.jl index 359217f..7666104 100644 --- a/src/precompile.jl +++ b/src/precompile.jl @@ -29,8 +29,8 @@ function _precompile_() precompile(Tuple{typeof(convert),Type{T},S}) precompile(Tuple{typeof(convert),Type{S},T}) end - # display in the terminal and into buffers (e.g. `repr`) - for IOT in (IOContext{Base.TTY}, IOContext{IOBuffer}, IOBuffer) + # display in the terminal, into pipes and into buffers (e.g. `repr`) + for IOT in (IOContext{Base.TTY}, IOContext{Base.PipeEndpoint}, IOContext{IOBuffer}, IOBuffer) precompile(Tuple{typeof(show),IOT,T}) precompile(Tuple{typeof(print),IOT,T}) precompile(Tuple{typeof(show),IOT,MIME"text/plain",T}) From d7c9e8b71e45cc0c68214c45597fb615bb3a90da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4cker?= Date: Sun, 18 Oct 2026 05:24:31 +0200 Subject: [PATCH 3/3] Only precompile for `N0f8` It turns out that compiling only `N0f8` covers enough generic code so that the latency of the other methods for the other types is acceptable on typical REPL usage. A one-time delay of half a second is okay on the REPL. A delay of 2.5 seconds feels sluggish. Within package usage, the packages can and should precompile for their specific use cases. ---- :robot: | | master | previous PR | current PR | |---|---:|---:|---:| | image (KiB) | 2653 | 4016 | 3277 | | display `N0f8` | 2511 | 274 | 261 | | display `N0f16` | 2144 | 196 | 444 | | display `Q0f7` | 2510 | 473 | 485 | | display `Q0f15` | 2500 | 607 | 537 | | core `N0f16` | 155 | 106 | 207 | | core `Q0f7` | 363 | 271 | 257 | | core `Q0f15` | 327 | 220 | 275 | Julia 1.13.1, time in ms of the first use in a fresh process, fastest of 5, pinned to one core. "display" is the first `show` of a value and of a 2-element vector plus `print`, into a terminal (pipes give the same numbers within noise). "core" is the first arithmetic, rounding, conversion and `rand`. --- src/precompile.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/precompile.jl b/src/precompile.jl index 7666104..767d876 100644 --- a/src/precompile.jl +++ b/src/precompile.jl @@ -2,8 +2,8 @@ using Random function _precompile_() ccall(:jl_generating_output, Cint, ()) == 1 || return nothing - normedtypes = (N0f8, N0f16) # precompiled Normed types - realtypes = (Float16, Float32, Float64, Int) # types for mixed Normed/Real operations + normedtypes = (N0f8,) # N0f8 is most common and accelerates others, too + realtypes = (Float16, Float32, Float64, Int) # types for mixed Normed/Real operations for T in normedtypes for f in (+, -, abs, eps) # unary operations precompile(Tuple{typeof(f),T})