profiling zsh startup
last updated: Jan 24, 2024
https://www.bigbinary.com/blog/zsh-profiling
Inspired by Larry Tratt linking to Thorsten Ball, I took a quick look at shell startup time this morning.
zsh has a built-in profiler, which is very handy. Before I ran it, my shell startup was about 373ms:
$ hyperfine --shell=none "zsh -i -c exit"
Benchmark 1: zsh -i -c exit
Time (mean ± σ): 373.2 ms ± 13.3 ms [User: 210.6 ms, System: 148.3 ms]
Range (min … max): 364.0 ms … 409.5 ms 10 runs
When I ran it, I saw that compinit
, which initializes zsh's completion system, was taking most of that time:
$ ZDOTDIR=/tmp/profile_zshrc zsh
num calls time self name
-----------------------------------------------------------------------------------
1) 1 59.07 59.07 31.84% 59.07 59.07 31.84% compdump
2) 1 185.32 185.32 99.89% 54.74 54.74 29.51% compinit
3) 795 54.11 0.07 29.16% 54.11 0.07 29.16% compdef
4) 2 17.40 8.70 9.38% 17.40 8.70 9.38% compaudit
5) 3 0.20 0.07 0.11% 0.20 0.07 0.11% add-zsh-hook
6) 1 0.00 0.00 0.00% 0.00 0.00 0.00% delta_sidebyside
So I searched (Kagi'd?) "slow compinit", and found that most of the time is taken up in parsing a dumpfile that doesn't change that often. So I replaced this line:
autoload -Uz compinit && compinit
with these ones, which will only run compinit
without -C
if it's been 24 hours since the dumpfile was last opened:
autoload -Uz compinit
for dump in ~/.zcompdump(N.mh+24); do
compinit
done
compinit -C
And now my shell spawns much more quickly:
$ hyperfine --shell=none "zsh -i -c exit"
Benchmark 1: zsh -i -c exit
Time (mean ± σ): 45.3 ms ± 3.5 ms [User: 21.4 ms, System: 16.6 ms]
Range (min … max): 42.2 ms … 64.6 ms 46 runs