Cover Image

Seit einiger Zeit nervt es mich, dass mein ZSH Shell sich gefühlt sehr träge öffnet. Heute habe ich mich endlich an den Rechner gesetzt und versucht das ganze etwaszu beschleunigen. Aber was soll ich denn beschleunigen?

Nach kurzer Recherche habe ich herausgefunden, dass es einen eingebauten Profiler in der ZSH gibt. Diesen kann am aktivieren indem man in der ersten Zeile der ~/.zshrc folgendes einträgt:

zmodload zsh/zprof

Danach wird beim Starten einer neuen Shell alle Befehle und der deren Laufzeit im Hintergrund aufgezeichnet. Ein Protokoll kann man erhalten indem man den Befehl zprof aufruft. Am besten startet man eine neuen Shell und beendet diese direkt wieder. Die Gesamtlaufzeit lässt sich zusätzlich mit dem netten time Befehl ermitteln.

time zsh -i -c "zprof && exit"

Die Ausgabe meiner Shell sah nun wie folgt aus.

num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    1         120,03   120,03   97,98%     52,17    52,17   42,59%  zgen-init
 2)    2          27,64    13,82   22,56%     27,64    13,82   22,56%  compinit
 3)    1          14,58    14,58   11,90%     14,58    14,58   11,90%  handle_completion_insecurities
 4)    1           7,56     7,56    6,17%      7,56     7,56    6,17%  _zsh_highlight_bind_widgets
 5)    1           6,58     6,58    5,37%      6,45     6,45    5,26%  _zsh_highlight_load_highlighters
 6)    3           2,97     0,99    2,43%      2,97     0,99    2,43%  colors
 7)    4           1,75     0,44    1,43%      1,75     0,44    1,43%  _update_prompt
 8)    1           1,77     1,77    1,44%      1,74     1,74    1,42%  powerlevel9k_vcs_init
 9)    1           1,25     1,25    1,02%      1,25     1,25    1,02%  detect-clipboard
10)   36           1,44     0,04    1,18%      1,19     0,03    0,97%  set_default
11)    1           1,10     1,10    0,89%      1,10     1,10    0,89%  termColors
12)   10           1,02     0,10    0,83%      1,02     0,10    0,83%  compdef
13)    7           1,00     0,14    0,82%      1,00     0,14    0,82%  add-zsh-hook
14)    1           5,10     5,10    4,16%      0,77     0,77    0,63%  prompt_powerlevel9k_setup
15)    3           0,62     0,21    0,51%      0,62     0,21    0,51%  is-at-least
16)   41           0,31     0,01    0,25%      0,31     0,01    0,25%  defined
17)    1           0,18     0,18    0,15%      0,18     0,18    0,15%  (anon)
18)    2           0,06     0,03    0,05%      0,06     0,03    0,05%  segment_in_use
19)    1           0,08     0,08    0,07%      0,04     0,04    0,04%  print_deprecation_warning
20)    2           0,04     0,02    0,03%      0,04     0,02    0,03%  env_default
21)    1           0,04     0,04    0,04%      0,03     0,03    0,03%  zgen
22)    1           0,02     0,02    0,02%      0,02     0,02    0,02%  bashcompinit
23)    1           0,01     0,01    0,01%      0,01     0,01    0,01%  zgen-saved

Wie man sieht geht ein großer Teil der Zeit auf zgen init drauf.

Nicht vergessen sollte man, den Profiler in der .zshrc Datei nach dem Benchmark wieder zu deaktivieren!

Umstellung von zgen auf zplug

Im Zuge der Performance-Analyse habe ich meine ZSH Plugin von zgen auf zplug umgestellt was einiges schneller sein soll. Das scheint bei mir auch einiges gebracht zu haben. Die Startgeschwindigkeit hat sich um ca. 20% verbessert. Eine kleine Anleitung zur Migration gibt es hier: https://github.com/zplug/zplug/wiki/Migration

Meine Logik zum Laden von zplug Plugin sieht nun so aus:

# Check if zplug is installed
if [[ ! -d ~/.zplug ]]; then
  git clone https://github.com/zplug/zplug ~/.zplug
  source ~/.zplug/init.zsh && zplug update --self
fi

source "${HOME}/.zplug/init.zsh"

# Make sure to use double quotes to prevent shell expansion
zplug "plugins/command-not-found", from:oh-my-zsh
zplug "plugins/git", from:oh-my-zsh
zplug "plugins/sudo", from:oh-my-zsh
zplug "plugins/ssh", from:oh-my-zsh
zplug "plugins/z", from:oh-my-zsh
zplug "plugins/shrink-path", from:oh-my-zsh
zplug "bhilburn/powerlevel9k", use:powerlevel9k.zsh-theme

zplug "zsh-users/zsh-completions"
zplug "zsh-users/zsh-autosuggestions"
zplug "zsh-users/zsh-syntax-highlighting", defer:2
zplug "zsh-users/zsh-history-substring-search", defer:3

zplug "junegunn/fzf", use:"shell *.zsh"
zplug "junegunn/fzf", as:command, hook-build:"./install --bin", use:"bin/{fzf-tmux,fzf}"

# Install packages that have not been installed yet
if ! zplug check; then
    printf "Install? \[y/N\]: "
    if read -q; then
        echo; zplug install
    else
        echo
    fi
fi

zplug load

Bei der Analyse habe ich gleich noch ein paar Dinge entfernt die ich nicht wirklich benötigt habe. Jetzt startet bei mir eine Shell wieder blitzschnell.

time zsh -i -c "exit"
zsh -i -c "exit"  0,19s user 0,09s system 113% cpu 0,244 total