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!!
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.
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 👍
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.)
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.
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.
>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".
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!!
________________________________________________________
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.
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.
➜ 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!
Wow, thanks for this! I got it down from 400ms to 120ms.
❯ time zsh -i -c exit
zsh -i -c exit 0.40s user 0.17s system 95% cpu 0.606 total
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.
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
```
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
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
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.
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!)
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
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.
>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
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