My shell is slooow!
This is my first blog post for years. I have been finding excuses for not writing one over the years, but I feel this is the right time.
I was coding as usual when I started something odd with my shell. I have done few adjustments
.zshrc file and out of a sudden it became very slow to spawn a new shell. As a person
who has a obsession with performance, it became my duty to find out the problem.
I have done some measurements:
> time /bin/zsh -i -c exit /bin/zsh -i -c exit 0.30s user 0.41s system 34% cpu 2.077 total
2 secs just for spawning a new shell? There is really something odd. Well at this point,
I thought using some kind of profiler on my Mac like samples, but then I decided it will be simpler
to go over the things on
.zshrc file comment out some of them to find out what is causing this annoying
After a while, I found 3 things:
[ -s "$NVM_ROOT/nvm.sh" ] && \. "$NVM_ROOT/nvm.sh" # This loads nvm [ -s "$NVM_ROOT/bash_completion" ] && \. "$NVM_ROOT/bash_completion" # This loads nvm bash_completion export PATH=$RVM_ROOT/bin:$PATH source $RVM_ROOT/scripts/rvm export PATH=$PYENV_ROOT/bin:$PATH eval "$(pyenv init --path)"
As you can see, I am frequently using
pyenv. That is because my day-to-day job requires jumping between
different versions of Node/Python/Ruby currently.
When I comment out above code, the startup time decreases to
lazyload extension to the rescue
Most of the time, I don’t need these stuff to be initialized at all. However, I need them when I need them.
There is a extension called
lazyload that takes a command and do the initialization only once
when you need them. Within few minutes, I arrived at following code:
lazyload nvm -- '[ -s "$NVM_ROOT/nvm.sh" ] && \. "$NVM_ROOT/nvm.sh" # This loads nvm [ -s "$NVM_ROOT/bash_completion" ] && \. "$NVM_ROOT/bash_completion" # This loads nvm bash_completion' lazyload rvm -- 'export PATH=$RVM_ROOT/bin:$PATH source $RVM_ROOT/scripts/rvm' lazyload pyenv -- 'export PATH=$PYENV_ROOT/bin:$PATH eval "$(pyenv init --path)"'
Which was exactly what I needed!
.zshrc file: https://github.com/sumerc/dotfiles/blob/main/zshrc
zsh-lazyload extension: https://github.com/qoomon/zsh-lazyload
One final thought
Right now, I am really wondering why these tools do not provide this kind of lazy-loading by default. It seems far better practice especially for people that have to install lots of different tools.