Den Start der Zsh beschleunigen
Geschrieben am 08-02-2025 - ⧖ 12 minDie Konfigurationsdateien meiner Zsh wurden über die Jahre immer größer und umfangreicher. Ich habe jetzt schon einiges rausgeworfen, aber der Start der Shell ist immer noch langsam. Sehr langsam:
$ time zsh -i -c exit
zsh -i -c exit 1.22s user 1.05s system 98% cpu 2.314 total
Die einfachste, aber auch aufwendigste Form der Fehlersuche ist, alles zu
kommentieren, eine Shell zu starten, zu prüfen ob sich was geändert hat und dann
nach und nach weitere Abschnitte der Konfigurationsdatei hinzuzufügen und das
ganze zu wiederholen. Alternativ dazu kann man auch Modul zsh/zprof
laden und damit auf Fehlersuche gehen. Der Vorgang ist denkbar einfach. Man fügt
zmodload zsh/zprof
an den Anfang der ~/.zshrc und zprof
ans Ende hinzu;
wenn man anschließend eine neue Shell startet, bekommt man (also in dem Fall
ich) folgende Ausgabe zu sehen:
num calls time self name
-----------------------------------------------------------------------------------
1) 2 1062.07 531.03 60.31% 517.73 258.86 29.40% nvm_auto
2) 4 521.46 130.36 29.61% 277.64 69.41 15.77% nvm
3) 2 263.98 131.99 14.99% 263.98 131.99 14.99% compdump
4) 1702 221.30 0.13 12.57% 221.30 0.13 12.57% compdef
5) 2 693.30 346.65 39.37% 179.38 89.69 10.19% compinit
6) 2 207.43 103.71 11.78% 179.06 89.53 10.17% nvm_ensure_version_installed
7) 2 36.27 18.14 2.06% 35.97 17.98 2.04% nvm_die_on_prefix
8) 4 28.83 7.21 1.64% 28.83 7.21 1.64% compaudit
9) 2 28.36 14.18 1.61% 28.36 14.18 1.61% nvm_is_version_installed
10) 1 12.27 12.27 0.70% 8.46 8.46 0.48% nvm_validate_implicit_alias
11) 1 22.88 22.88 1.30% 8.42 8.42 0.48% nvm_is_valid_version
12) 1 3.75 3.75 0.21% 3.75 3.75 0.21% nvm_echo
13) 1 2.19 2.19 0.12% 2.19 2.19 0.12% nvm_version_greater_than_or_equal_to
14) 1 1.60 1.60 0.09% 1.60 1.60 0.09% colors
15) 14 1.56 0.11 0.09% 1.56 0.11 0.09% add-zsh-hook
16) 1 1.34 1.34 0.08% 1.34 1.34 0.08% kitty-integration
17) 8 0.30 0.04 0.02% 0.30 0.04 0.02% nvm_npmrc_bad_news_bears
18) 1 0.29 0.29 0.02% 0.29 0.29 0.02% is-at-least
19) 1 0.19 0.19 0.01% 0.19 0.19 0.01% (anon) [/home/dope/.zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh:458]
20) 1 0.14 0.14 0.01% 0.14 0.14 0.01% _omp_cleanup
21) 2 0.12 0.06 0.01% 0.12 0.06 0.01% nvm_has
22) 1 0.08 0.08 0.00% 0.08 0.08 0.00% colorize_man
23) 1 0.76 0.76 0.04% 0.08 0.08 0.00% enable_you_should_use
24) 1 0.15 0.15 0.01% 0.07 0.07 0.00% complete
25) 1 0.41 0.41 0.02% 0.07 0.07 0.00% disable_you_should_use
26) 2 1062.13 531.07 60.31% 0.06 0.03 0.00% nvm_process_parameters
27) 1 3.80 3.80 0.22% 0.05 0.05 0.00% nvm_err
28) 1 0.03 0.03 0.00% 0.03 0.03 0.00% _omp_create_widget
29) 2 0.02 0.01 0.00% 0.02 0.01 0.00% nvm_is_zsh
30) 1 0.02 0.02 0.00% 0.02 0.02 0.00% bashcompinit
[ Die originale Ausgabe ist noch länger, aber nicht wirklich relevant ]
So.. mein erster Gedanke war "ich hab NVM installiert?!" und siehe da.. Ja. Habe ich.
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
if [ -f /usr/share/nvm/init-nvm.sh ]; then
source /usr/share/nvm/init-nvm.sh
fi
Eine Option ist, den Müll einfach zu kommentieren und fertig, was meine
Vorgehensweise war. Wer NVM (wieso auch immer) benötigt, kann einen Blick auf
das Plugin zsh-nvm-lazy-load
werfen.
Nachdem man den Start von NVM deaktiviert hat, sieht die Welt schon etwas besser
aus:
$ time zsh -i -c exit
$ zsh -i -c exit 0.31s user 0.17s system 65% cpu 0.729 total
Die nächsten beide Kandidaten sind dann compaudit
, compinit
und comdef
.
Alles was bei der Zsh mit "comp" anfängt, lädt das Completionsystem aka
zshcompsys(1) und muss - zumindest in
meinem Fall - geladen werden. Nur wird in meinem Fall compaudit
zweimal
aufgerufen; so.. was macht compaudit
? Use the source luke!
# https://github.com/zsh-users/zsh/blob/master/Completion/compaudit
[...]
# Audit the fpath to assure that it contains all the directories needed by
# the completion system, and that those directories are at least unlikely
# to contain dangerous files. This is far from perfect, as the modes or
# ownership of files or directories might change between the time of the
# audit and the time the function is executed.
# This function is designed to be called from compinit, which assumes that
# it is in the same directory, i.e., it can be autoloaded from the initial
# fpath as compinit was. Most local parameter names in this function must
# therefore be the same as those used in compinit.
[...]
und die wird dann am Ende von compinit
aufgerufen. Mit anderen Wort "Brauch
ich also auch *gnarf*".
Note
Wenn man zprof
mit der Option --sourcetrace
ausführt, wird jede Datei
ausgegeben die abgearbeitet wird
Also weiter im Text.. kitty-integration
brauchewill ich.
add-zsh-hook
wird u. a. von meinem Prompt genutzt. Das Modul
is-at-least
wird genutzt um zu prüfen ob "mindestens $ZSH_VERSION installiert"
ist und das wird von zsh-autosuggestions
genutzt. colorize_man
fliegt raus, weil bat
mein $MANPAGER ist, aber zsh-you-should-use
bleibt drin (ist manchmal ganz hilfreich) und colors
macht das ganze
übersichtlicher (finde ich zumindest).
Wenn man compinit
in seiner ~/.zshrc initiiert, wird bei jedem Aufruf der Zsh
geprüft ob ~/.zcompdump neu erstellt werden muss. Abstellen kann man das relativ
einfach mit folgenden Zeilen:
autoload -Uz compinitfor dump in ~/.zcompdump(N.mh+24); do
compinit
donecompinit -C
Die Option -C
überspringt die Prüfung und den Aufruf von compaudit
(mehr
dazu in den Sourcen von compinit).
Ein anschließender Start der Zsh ging danach schon um einiges schneller:
$ time zsh -i -c exit
$ zsh -i -c exit 0.26s user 0.12s system 61% cpu 0.619 total
was daran lag, das die Zsh bei weitem weniger Aufrufe abzuarbeiten hatte
num calls time self name
-----------------------------------------------------------------------------------
1) 1 15.51 15.51 72.65% 15.51 15.51 72.65% compinit
2) 1 2.64 2.64 12.35% 2.64 2.64 12.35% colors
3) 14 1.43 0.10 6.71% 1.43 0.10 6.71% add-zsh-hook
4) 1 0.97 0.97 4.56% 0.97 0.97 4.56% kitty-integration
5) 1 0.24 0.24 1.10% 0.24 0.24 1.10% is-at-least
6) 1 0.18 0.18 0.82% 0.18 0.18 0.82% (anon) [/home/dope/.zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh:458]
7) 1 0.12 0.12 0.58% 0.12 0.12 0.58% _omp_cleanup
8) 1 0.10 0.10 0.46% 0.10 0.10 0.46% compdef
9) 1 0.75 0.75 3.52% 0.07 0.07 0.33% enable_you_should_use
10) 1 0.37 0.37 1.74% 0.07 0.07 0.32% disable_you_should_use
11) 1 0.03 0.03 0.13% 0.03 0.03 0.13% _omp_create_widget
Das ganze könnte man jetzt noch weiter optimieren, in dem man z. B. auf das Prompt-Theme verzichtet und stattdessen PS1 mit "#" oder "$" setzt, aber das würde bei mir ausarten, denn ich will einen visuellen Hinweis im PS1 ob ich via SSH/Tmux/root|user arbeite, auf welchem Host ich eingeloggt bin und welches mein $PWD ist. Ist zwar mit den Boardmitteln der Zsh machbar, aber da kann ich auch gleich bei Oh My Posh bleiben.