zsh-syntax-highlighting icon indicating copy to clipboard operation
zsh-syntax-highlighting copied to clipboard

syntax highlighting is super slow in WSL2

Open A1ex-N opened this issue 4 years ago • 25 comments

On WSL the zsh syntax highlighting worked perfectly, but in WSL2 it's extremely slow. When you type there's about a 1 second delay before your input is actually shown. Not sure if it's a problem with WSL2 or the highlighting itself.

A1ex-N avatar Dec 29 '20 04:12 A1ex-N

What are the version numbers of zsh and zsh-syntax-highlighting in each environment?

danielshahaf avatar Dec 29 '20 11:12 danielshahaf

@danielshahaf I'm on zsh 5.8 and the latest version of zsh syntax highlighting installed via git clone. I'm using Ubuntu-20,04 via WSL2

A1ex-N avatar Dec 29 '20 11:12 A1ex-N

@danielshahaf https://github.com/danielshahaf I'm on zsh 5.8 and the latest version of zsh syntax highlighting installed via git clone. I'm using Ubuntu-20,04 via WSL2

What are the version numbers on the WSL1 environment?

Assuming everything is the same except WSL1 v. WSL2… well, I don't know of any developers who use WSL (either version), so you may have to debug this yourself. Getting a minimal reproducer (one that doesn't even involve z-sy-h, if possible), and/or employing zprof/set -x to identify the slow part, would be reasonable starting points.

danielshahaf avatar Dec 30 '20 01:12 danielshahaf

encounter the same issue

Purewhiter avatar Jan 11 '22 11:01 Purewhiter

To answer the deleted comment: z-sy-h uses $PATH via the type builtin to determine whether a command word should be highlighted in green or red. However, an expensive-to-access $PATH wouldn't by itself explain slowness after the command word has finished being inputted, since both z-sy-h and zsh memoize the results of filesystem queries. Related knobs include zsh's PATH_DIRS and HASH_CMDS options and related options in that section, and the rehash builtin and style. z-sy-h's memoization takes place in _zsh_highlight_main__type.

That can be ruled out simply by trying to reproduce the issue under zsh -f (and then sourcing zsh-syntax-highlighting.zsh manually).

danielshahaf avatar Apr 23 '22 18:04 danielshahaf

I noticed some sluggish behaviour while on WSL2 but nothing like a 1 second delay (if I had to guess about ~200ms). The only thing that should be slow on WSL2 would be the NTFS mounts from the windows file system as they are mounted by using 9P. I have added the windows mount in the directory blacklist as mentioned here: https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters/main.md#parameters

ZSH_HIGHLIGHT_DIRS_BLACKLIST+=(/mnt/c)

This makes the "cold" highlighting after a fresh start a bit faster. Surprisingly enough it still recognizes commands like code as valid commands and highlights them green/red accordingly although being located in /mnt/c/. However, as mentioned by @danielshahaf the Path lookups are memorized and it shouldn't make that big difference.

twobiers avatar Aug 21 '22 12:08 twobiers

Adding ZSH_HIGHLIGHT_DIRS_BLACKLIST doesn't seem to change anything.

Is there anything else to try?

wywywywy avatar Nov 07 '22 11:11 wywywywy

Try zsh 5.9. I don't know that any maintainer has WSL, so, y'all may need to help investigate. Does it reproduce in zsh -f? Do make check and make perf work? Does zsh/zprof show anything (don't forget to zprof -c before starting the timed section)? Can you try a different terminal?

(I just posted that on #899, but it works equally well as an answer to @wywywywy.)

danielshahaf avatar Nov 11 '22 19:11 danielshahaf

I solved this by excluding windows directories from $PATH by adding following in /etc/wsl.conf. Create the file if it doesn't exist

[interop]
appendWindowsPath = false

Then restart wsl with

wsl --shutdown

It's also possible to disable the possibility to run windows binaries inside WSL instances with the following in /etc/wsl.conf. I didn't do this myself since the above solved my performance problems I had

enabled = false

amimof avatar Jan 17 '23 13:01 amimof

I solved this by excluding windows directories from $PATH by adding following in /etc/wsl.conf. Create the file if it doesn't exist

[interop]
appendWindowsPath = false

For my use case I still want some Windows paths. For example the code command is found in /mnt/c/Users/<user>/AppData/Local/Programs/Microsoft VS Code/bin

patrick-5546 avatar Jan 17 '23 17:01 patrick-5546

I solved this by excluding windows directories from $PATH by adding following in /etc/wsl.conf. Create the file if it doesn't exist

[interop]
appendWindowsPath = false

For my use case I still want some Windows paths. For example the code command is found in /mnt/c/Users/pcrei/AppData/Local/Programs/Microsoft VS Code/bin

You could make some aliases for your common windows commands if you still wanted to exclude the windows directories from the $PATH. For example alias code=/mnt/c/vscode.exe

A1ex-N avatar Jan 17 '23 23:01 A1ex-N

I ended up manually adding that bin to PATH, which didn't noticeably slow down performance:

export PATH="/mnt/c/Users/<user>/AppData/Local/Programs/Microsoft VS Code/bin:$PATH"

I wonder which windows paths causes the poor performance of syntax highlighting.

patrick-5546 avatar Jan 18 '23 01:01 patrick-5546

I ended up manually adding that bin to PATH, which didn't noticeably slow down performance:

export PATH="/mnt/c/Users/<user>/AppData/Local/Programs/Microsoft VS Code/bin:$PATH"

I wonder which windows paths causes the poor performance of syntax highlighting.

I imagine it's not any specific paths that causes the slowdown, it's probably just the number of paths.

A1ex-N avatar Jan 18 '23 04:01 A1ex-N

@amimof Thanks for the info that removing some entries from $path resolves the slowness.

First, I'd like to check whether there are any other causes of slowness at play here. So:

  1. After applying the workaround proposed in https://github.com/zsh-users/zsh-syntax-highlighting/issues/790#issuecomment-1385406603 by @amimof, does anyone observe slowness that isn't covered by some other open issue? [Note I haven't reviewed the workaround.]

  2. Does slowness happen at words other than command words? For instance, when completing --options, arguments to them, or positional arguments (filenames to ls(1), hostname to ping(1), etc.).

  3. There's caching going on, both at the zsh level (see the rehash builtin) and at the z-sy-h level (in _zsh_highlight_main__type()). Negative matches are cached at the z-sy-h level — to see that, run print -raC2 - "${(@kv)_zsh_highlight_main__command_type_cache}" and observe the none entries — so, in theory, once you've typed foobar in command position once, the next time you type foobar in command position will be highlighted quickly. Is that what happens?

danielshahaf avatar Jan 19 '23 09:01 danielshahaf

I wonder which windows paths causes the poor performance of syntax highlighting.

I imagine it's not any specific paths that causes the slowdown, it's probably just the number of paths.

WSL2 is well known to have poor performance interacting with Windows' filesystem. There's an open issue dating back to 2019: https://github.com/microsoft/WSL/issues/4197

Workarounds include working inside WSL2's filesystem or creating an NFS server and use that instead (which funnily enough, seems to work faster than the native WSL2's way of doing it).

This performance issue directly affects anything that has to do with Windows' path, to list a couple:

  • https://github.com/microsoft/WSL/issues/4234
  • https://github.com/kubernetes/kubectl/issues/1336
  • https://github.com/microsoft/WSL/issues/4401

I solved this by excluding windows directories from $PATH by adding following in /etc/wsl.conf. Create the file if it doesn't exist

[interop]
appendWindowsPath = false

This workaround "solves" the problem. By removing Window's paths from WSL2 we won't take the performance hit of doing lookups outside Linux... but we lose a bit of the cool integration with Windows.

Using ZSH_HIGHLIGHT_DIRS_BLACKLIST should help, but I'm not sure why it still feels slow... it's as if there were still some lookups happening on Windows's filesystem. Maybe there's some other paths that are symlinks to Windows? I'm not sure how to go about trying to figure that one out.

From what I can gather, the /mnt/c/WINDOWS/System32 path has a lot of files and is most likely the culprit here: it has over 5k items!

So added this appendWindowsPath flag and re-added some of my Windows' paths to my .zshrc (including the Windows folder itself), and the slowness is gone for me (these are most likely what the average coder using WSL2 will need anyway):

# .zshrc
### Windows ###
export PATH="$PATH:/mnt/c/Users/lesmo/AppData/Local/Microsoft/WindowsApps"
export PATH="$PATH:/mnt/c/Users/lesmo/AppData/Local/Programs/Microsoft VS Code/bin"
export PATH="$PATH:/mnt/c/Program Files/Docker/Docker/resources/bin"
export PATH="$PATH:/mnt/c/ProgramData/DockerDesktop/version-bin"
export PATH="$PATH:/mnt/c/WINDOWS"

Maybe we just need to figure out why ZSH_HIGHLIGHT_DIRS_BLACKLIST doesn't seem to work?

lesmo avatar Jan 23 '23 07:01 lesmo

Sinuhé Coronel wrote on Mon, 23 Jan 2023 07:22 +00:00:

So added this appendWindowsPath flag and re-added some of my Windows' paths to my .zshrc (including the Windows folder itself), and the slowness is gone for me (these are most likely what the average coder using WSL2 will need anyway):

# .zshrc
### Windows ###
export PATH="$PATH:/mnt/c/Users/lesmo/AppData/Local/Microsoft/WindowsApps"
export PATH="$PATH:/mnt/c/Users/lesmo/AppData/Local/Programs/Microsoft VS Code/bin"
export PATH="$PATH:/mnt/c/Program Files/Docker/Docker/resources/bin"
export PATH="$PATH:/mnt/c/ProgramData/DockerDesktop/version-bin"
export PATH="$PATH:/mnt/c/WINDOWS"

This might be more readable with the array counterpart of $PATH:

path+=(
	/mnt/c/Users/lesmo/AppData/Local/Microsoft/WindowsApps
	/mnt/c/Users/lesmo/AppData/Local/Programs/Microsoft VS Code/bin
	/mnt/c/Program Files/Docker/Docker/resources/bin
	/mnt/c/ProgramData/DockerDesktop/version-bin
	/mnt/c/WINDOWS
)

Maybe we just need to figure out why `ZSH_HIGHLIGHT_DIRS_BLACKLIST` 
doesn't seem to work?

ZSH_HIGHLIGHT_DIRS_BLACKLIST only applies to words literally typed on the command line. It doesn't magically cause $PATH directories not to be hashed. That's actually a zsh functionality, not a z-sy-h one. So, perhaps this:

() {
  set -- $path # save $PATH without overwriting any user variables
  path=( /some /directories /that /can /be /stat\(2\)ed /performantly )
  rehash
  path=( "$@" )
}

With this, commands from other directories will only be runnable by their full paths, or after running rehash again.

May need to add an 'always' block, depending on how exactly the temporary value of $PATH is computed.

danielshahaf avatar Jan 24 '23 08:01 danielshahaf

I solved this by excluding windows directories from $PATH by adding following in /etc/wsl.conf. Create the file if it doesn't exist

[interop]
appendWindowsPath = false

Then restart wsl with

wsl --shutdown

It's also possible to disable the possibility to run windows binaries inside WSL instances with the following in /etc/wsl.conf. I didn't do this myself since the above solved my performance problems I had

enabled = false

@amimof Thanks, that's useful for me.

Mukiik avatar Feb 22 '23 17:02 Mukiik

marked, helped me as well

Mark4551124015 avatar Mar 07 '23 08:03 Mark4551124015

same problem here, but I still want to keep windows path in WSL2, because I often use windows commands like clip.exe, cmd.exe, etc. and I don't want to alias all command one by one, that will be annoying.

maybe there's a bug of ZSH_HIGHLIGHT_DIRS_BLACKLIST?

jteng2127 avatar Apr 27 '23 14:04 jteng2127

Thank you @amimof, it worked for me.

khaitranhq avatar Jul 09 '23 15:07 khaitranhq

Thank you! That helps a lot!

ShelpAm avatar Jul 19 '23 13:07 ShelpAm

Thank you @amimof, It's propery worked fine

BearyDevs avatar Sep 30 '23 01:09 BearyDevs