I have recently switched my machine at work from Linux to Window (for many reasons that are beyond this post). And to keep using some of the tools I’m familiar with, I turned to WSL (Windows Subsystem for Linux). It is reasonably good for the most part¹. One thing that was not so good, was the initialization time of zsh
, which was taking roughly 20s when opening on WSL. I have used zprof in the past to identify why zsh
was taking so long to start on my Linux machine, so I did the same now for my WSL setup.
To my surprise, what was taking the most time, was initializing the completions (compinit
) and it’s subsequent calls (810x compdef
):
num calls time self name
-----------------------------------------------------------------------------------
1) 2 3735.87 1867.94 52.48% 1313.69 656.84 18.45% compinit
2) 810 1103.52 1.36 15.50% 1103.52 1.36 15.50% compdef
3) ...
I’m not entirely sure on why this happens on WSL only (as I have the same dotfile in my Linux); but I did find other people that were facing a similar issue on “slow systems” and suggested to use .zcompdump
to backup and restore the results of compinit
once a day.
The Solution
Similar to gist
above, I attempted to cache the results into a file and load them whenever opening zsh
. If there is already a file for today, then use it.
Here’s how I’ve done it:
current=$ZSH_CONFIG/.zcompdump-$(date '+%Y%m%d')
if [ -f $current ]; then
compinit -C $current
else
compinit -d $current
fi
Note that $ZSH_CONFIG
is my zsh
config folder. This could be changed by $HOME
or whatever other folder fits your needs.
Adding a check to environment
First, I don’t know exactly all the side effects of managing my own .zcompdump
. I imagine that if any new completions are added given any package I installed, I would have to run this to make sure the completions are regenerated. For this reason, I’m adding a check to use this workaround only on WSL.
This answer from stackoverflow did the tick for me.
Here’s how the code looks like³:
# Determine if on WSL
if grep -q Microsoft /proc/version; then
ON_WSL=1
else
ON_WSL=0
fi
#...
autoload -Uz compinit
if [[ $ON_WSL == 0 ]]; then
compinit
else
# Save completion to cache since it takes too much time to load on WSL
current=$ZSH_CONFIG/.zcompdump-$(date '+%Y%m%d')
if [ -f $current ]; then
compinit -C $current
else
compinit -d $current
fi
fi
Removing old dumps
Another idea is to remove any previous dumps in case zsh
needs to generate a new one, to avoid cluttering the folder with many .zcompdump
files for each day I’ve logged in my computer. This can be done by removing all files matching .zcompdump-*
before creating the new file dump file.
current=$ZSH_CONFIG/.zcompdump-$(date '+%Y%m%d')
if [ -f $current ]; then
compinit -C $current
else
rm $ZSH_CONFIG/.zcompdump-* 2>/dev/null
compinit -d $current
fi
Plus, add a 2>/dev/null
to redirect all error output to null
in case no .zcompdump
files were created and avoid having weird error messages when opening zsh
³.
Conclusion
I’ve been trying to do weekly revisions of my development environment, sometimes it’s on my personal setup and sometimes on my work machine. It’s kind of challenging since I have a Linux for personal projects and any Open Source contribution and (now) a Windows machine for my daily job. I don’t spent as much time as I wanted on Linux now but with WSL I have found some familiarity with the tools I was using in the past years.
In case you’re interested here’s the latest version of my .zshrc
file.
Footnotes
¹ Unfortunately my company’s Windows image isn’t the latest so I’m still stuck with some rough around the edges version of WSL. Nonetheless most things are working fine.
² Initially, I had the $ON_WSL
to be either set or unset, and checking it using if [ -z $ON_WSL]
; but if (for any god forsaken reason) I assign this variable anywhere else (even to a negative value), of if my current environment sets it somewhere else, I’d have problems here. So I’m being explicit about the flag being on or off.
³ I might have found a bug on WSL while trying this. Redirecting error output does not work for glob. Running rm .zcompdump- &>/dev/null
correctly redirects the error and nothing is shown on screen; but rm .zcompdump-* &>/dev/null
shows the error zsh: no matches found: .zcompdump-*
on the terminal. I didn’t look any further into this. Go figure.
#ramble #zsh #optimization #bash
⇦ Back Home | ⇧ Top |
If you hated this post, and can't keep it to yourself, consider sending me an e-mail at fred.rbittencourt@gmail.com or complain with me at Twitter X @derfrb. I'm also occasionally responsive to positive comments.