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
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.
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
$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
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
¹ 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.