31 Comments
Jan 15Liked by Thorsten Ball

My startup time was around 400ms, mostly because of NVM. I was using bash, and switched over to zsh. I'm now lazy loading NVM using the oh-my-zsh plugin and now my startup time is around 100ms. Not very fast but an improvement nonetheless. Thanks!!

Expand full comment
Jan 14Liked by Thorsten Ball

________________________________________________________

Executed in 148.21 millis fish external

usr time 45.35 millis 66.00 micros 45.29 millis

sys time 58.13 millis 512.00 micros 57.62 millis

i use fish, with 3 plugins. previously, like an year ago i used to use oh-my-zsh, even while enabling very few plugins, it used to take so much time to load. So, moved to fish with very few plugins.

Expand full comment
Jan 14Liked by Thorsten Ball

Thanks for writing post. This gave me curiousity to check my shell startup time. I found it takes ~1.2 seconds to load SHELL and after fixing nvm (culprit who was taking most of time) it has reduced to 0.121ms which is great 👍

Thank you once again.

Expand full comment
Jan 14Liked by Thorsten Ball

➜ dotfiles git:(main) ✗ for i in $(seq 1 10); do time $SHELL -i -c exit; done

$SHELL -i -c exit 0.03s user 0.00s system 99% cpu 0.030 total

$SHELL -i -c exit 0.02s user 0.01s system 99% cpu 0.029 total

$SHELL -i -c exit 0.02s user 0.00s system 98% cpu 0.029 total

$SHELL -i -c exit 0.02s user 0.01s system 99% cpu 0.027 total

$SHELL -i -c exit 0.02s user 0.00s system 98% cpu 0.028 total

$SHELL -i -c exit 0.02s user 0.01s system 99% cpu 0.028 total

$SHELL -i -c exit 0.03s user 0.00s system 99% cpu 0.027 total

$SHELL -i -c exit 0.02s user 0.00s system 99% cpu 0.027 total

$SHELL -i -c exit 0.02s user 0.01s system 99% cpu 0.028 total

$SHELL -i -c exit 0.02s user 0.01s system 99% cpu 0.028 total

but it used to take ~500ms with nvm, then found about lazy-loading it on GH (linked blogs show similar solutions):

https://github.com/nvm-sh/nvm/issues/1242#issuecomment-346946356

I'll give the zsh comp optimizations a try and report back, thanks!

Expand full comment
Jan 14Liked by Thorsten Ball

Wow, thanks for this! I got it down from 400ms to 120ms.

Expand full comment
Jan 14·edited Jan 14Liked by Thorsten Ball

❯ time zsh -i -c exit

zsh -i -c exit 0.40s user 0.17s system 95% cpu 0.606 total

Expand full comment

I don't care how long the shell is starting (currently around 400ms) as long as I have immediatly the prompt to type.

What changed my approach is Z-Init (Zi) https://github.com/zdharma/zi#calling-compinit-without-turbo-mode which lazy load a lot of things. So I can keep the "fluff" and they just appear as I have already started to type my commands.

Expand full comment

If you want to easily compare the timing of a command, use the multitime tool

https://tratt.net/laurie/src/multitime/

Here is what it looks like on my computer:

```

[cyril:~] % multitime -n 10 zsh -i -c exit

===> multitime results

1: zsh -i -c exit

Mean Std.Dev. Min Median Max

real 0.219 0.019 0.188 0.217 0.262

user 0.118 0.013 0.103 0.119 0.142

sys 0.062 0.011 0.047 0.064 0.082

[cyril:~] % multitime -n 10 bash -i -c exit

exit

exit

exit

exit

exit

exit

exit

exit

exit

exit

===> multitime results

1: bash -i -c exit

Mean Std.Dev. Min Median Max

real 0.209 0.008 0.203 0.206 0.232

user 0.176 0.007 0.167 0.176 0.188

sys 0.031 0.008 0.020 0.034 0.045

```

Expand full comment

I won.

; time rc -i -c exit

0,00 real 0,00 user 0,00 sys

; time rc -i -c exit

0,00 real 0,00 user 0,00 sys

; time rc -i -c exit

0,00 real 0,00 user 0,00 sys

; time rc -i -c exit

0,00 real 0,00 user 0,00 sys

; time rc -i -c exit

0,00 real 0,00 user 0,00 sys

Expand full comment
Jan 17·edited Jan 17

I really like having information about git status in my prompt (if I'm in a git repository), but as you say that can slow down "time to next prompt" to a noticeable degree (especially in large git repos). As an alternative to removing the information, however, I recommend that people look for async solutions. I'm currently using woefe/git-prompt.zsh, and it removes the drag from git information completely. (I've also seen solutions for zsh that use a daemon or a cache, but I haven't investigated those.)

https://github.com/woefe/git-prompt.zsh

Another good tool for timing how long it takes to get a next prompt is zsh-prompt-benchmark.

https://github.com/romkatv/zsh-prompt-benchmark

Expand full comment

With this test on my computer, bash takes 7 ms to start, or occasionally 6 ms. What is everybody doing that's taking 10x or 100x as long? That's bonkers.

Expand full comment

You are 10x faster than my macOS, room to improve for me

```

$ [~] $ time zsh -i -c exit

zsh -i -c exit 0.32s user 0.48s system 99% cpu 0.794 total

$ [~] $ time zsh -i -c exit

zsh -i -c exit 0.32s user 0.47s system 98% cpu 0.803 total

$ [~] $ time zsh -i -c exit

zsh -i -c exit 0.33s user 0.51s system 98% cpu 0.849 total

$ [~] $ time zsh -i -c exit

zsh -i -c exit 0.32s user 0.52s system 99% cpu 0.843 total

$ [~] $ time zsh -i -c exit

zsh -i -c exit 0.32s user 0.50s system 100% cpu 0.813 total

```

And ~~2x slower than my primary dev environment VM

```

divyendusingh@ubuntu:~/zoid/plv8ify$ time bash -i -c exit

exit

real 0m0.043s

user 0m0.003s

sys 0m0.008s

divyendusingh@ubuntu:~/zoid/plv8ify$ time bash -i -c exit

exit

real 0m0.041s

user 0m0.004s

sys 0m0.004s

divyendusingh@ubuntu:~/zoid/plv8ify$ time bash -i -c exit

exit

real 0m0.011s

user 0m0.004s

sys 0m0.003s

divyendusingh@ubuntu:~/zoid/plv8ify$ time bash -i -c exit

exit

real 0m0.010s

user 0m0.005s

sys 0m0.002s

divyendusingh@ubuntu:~/zoid/plv8ify$ time bash -i -c exit

exit

real 0m0.011s

user 0m0.004s

sys 0m0.003s

```

Probably why it didn't bother me as much! (not because I don't notice slowness in terminal, but other parts of my dev setup are slower!)

Expand full comment

Weighted clown shoes is such a good analogy!

I use hyperfine as a fancier `for i in $(seq)` and a `PS4=` trick to profile times of everything the rc file is doing: https://github.com/WillForan/dotconf/tree/master/bin/profile-bashrc

Expand full comment

Measuring with `hyperfine`, I get 13ms, with a "fancy" prompt. I wrote the prompt in Zig, which makes it easy to ensure that there are no allocations, no syscalls other than one `write()`, etc. I never measured it like this, but seems like it worked out quite well.

Expand full comment

>Think about it this way: (1) which program do you execute more often than your shell? (2) How many shells do you spawn every day? (3) How many other programs do you run every day that spawn your shell?

You seem to be conflating interactive (1, 2) and non-interactive shell invocations (3), here. The reality is that interactive shell startup time (here 0.02s for zsh with all the usual completions) doesn't matter as long as it's not noticeable; for the non-interactive case (the one spawned by other programs at a rate great enough to make that latency important), zsh is basically as instantaneous as dash or busybox (which are barren due to focus on POSIX compliance).

I guess the morale simply is "don't use zsh frameworks for wannabe ricers".

Related, a small latency comparison I did some ages ago: https://git.sr.ht/~q3cpma/interp_overhead/tree/master/item/results.txt

Expand full comment

zsh -i -c exit 0.26s user 0.21s system 20% cpu 2.323 total

zsh -i -c exit 0.12s user 0.07s system 90% cpu 0.207 total

zsh -i -c exit 0.12s user 0.07s system 90% cpu 0.210 total

zsh -i -c exit 0.12s user 0.07s system 91% cpu 0.209 total

zsh -i -c exit 0.12s user 0.07s system 90% cpu 0.205 total

Expand full comment