ohmyzsh: git_prompt_status is slow on cygwin
git_prompt_status is rather slow on cygwin, and on other platforms where spawning a subshell is slow. Two cases: (first, just calling the function, second is inside a fresh linux kernel tree. )
TheDauthi@Hera:~$ time (git_prompt_status)
( git_prompt_status; ) 0.21s user 0.41s system 97% cpu 0.636 total
TheDauthi@Hera:~/Projects/linux$ time (git_prompt_status)
( git_prompt_status; ) 2.41s user 9.50s system 228% cpu 5.216 total
(Not much we can do about the second one, it’s due to the slowness of the git status itself) Identical setup on linux:
billyconn@Hades:~$ time (git_prompt_status)
( git_prompt_status; ) 0.00s user 0.01s system 16% cpu 0.047 total
billyconn@Hades:~/Projects/linux$ time (git_prompt_status)
( git_prompt_status; ) 0.06s user 0.08s system 85% cpu 0.173 total
Tracking this down, it’s the spawning of the greps (which is no shock; cygwin emulation of fork is well-known, and grep is somehow particularly slow). I rewrote this function to use zsh builtins and an ugly bit of sed instead of spawning greps:
Cygwin:
TheDauthi@Hera:~$ time (git_prompt_status)
( git_prompt_status; ) 0.07s user 0.04s system 117% cpu 0.102 total
TheDauthi@Hera:~/Projects/linux$ time (git_prompt_status)
( git_prompt_status; ) 2.30s user 8.75s system 241% cpu 4.567 total
It’s faster on linux, too, but linux was already fast: Linux:
billyconn@Hades:~$ time (git_prompt_status)
( git_prompt_status; ) 0.00s user 0.00s system 0% cpu 0.008 total
billyconn@Hades:~/Projects/linux$ time (git_prompt_status)
( git_prompt_status; ) 0.06s user 0.09s system 104% cpu 0.137 total
https://github.com/TheDauthi/git-prompt-status
I didn’t make a pull request; this is in a frequently-used lib so I didn’t want to touch it without testing, if there’s even interest in using a modified version. I wrote a FEW tests (they’re in the test directory), but will try to add more. I also would like to know if/how you typically integrate tests, as what’s there is just something I hacked up in a couple of hours.
Not sure how the command works on OSX yet, don’t have a machine to test on until Monday. I suspect that the sed statements will need to be re-quoted. Wanted to gauge interest and get feedback before continuing.
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 3
- Comments: 18 (3 by maintainers)
Commits related to this issue
- Disabled git status on Cygwin See : https://github.com/robbyrussell/oh-my-zsh/issues/5486 — committed to FredDeschenes/dotfiles by FredDeschenes 7 years ago
It’s different code and does a different thing, but possibly the same underlying problem. We’re a bit off topic here, but your point is valid and should be noted for anyone coming across the problem: for a large codebase (or a very slow filesystem), anything calling git status underneath may be slow. I’ve seen several attempt to fix that, from trying to kill the git status process after a timeout to caching the output. I don’t think any of them have been successful yet. I think the current suggestion is to use
git config --add oh-my-zsh.hide-status 1in any slow git repository to make oh-my-zsh ignore building the status for that particular directory.I started out by looking at the outputs of
echo $PROMPT,echo $RPROMPT,echo $RPROMPT2andecho $PROMPT_COMMAND. That shows what functions are being called before/after each prompt. Testing each function separately using$(function-name)will show which one is taking its time. From there, it’s just a matter of taking apart the functions individually.If you’re on Cygwin, I’d give it an 98% chance of being extra subshells or commands (especially grep) being executed. Forking and running commands (including subshells) is extremely slow on cygwin, because it’s not really forking, it’s creating a process and then cloning the previous command’s entire data segment, stack, heap, etc. manually into the new process. The Windows kernel itself does support forking, but that functionality isn’t exposed to the win32 subsystem.
If you’re on another environment, the only real things I’ve seen used that killed performance in a prompt was a plugin function that scanned and parsed the history file and rewrote it after every command and one that was trying to do a git fetch after every one.