valid,invalid

関心を持てる事柄について

zshの起動が遅かったのでzprofでプロファイリングしながら起動速度を3倍速くした

(追記: 2021-07-18) 本記事の続編 => zshの起動がいつの間にか速くなっていた - valid,invalid

zshの起動速度が遅いのをずっと放置していたので改善した。もともと遅かったので自慢できる数字ではないが、とても大雑把に言うと起動時間がおよそ3秒→1秒と3倍速くなった

やったこと

zprofでボトルネック特定

今回はこの方法を知ることが出来たので一番の収穫だったかもしれない。

まず、単純にtimeコマンドで計測するとおおまかな処理時間はわかるが、ボトルネックがわからない。

# チューニング前の time コマンド実行結果
❯ for i in $(seq 1 10); do time zsh -i -c exit; done
zsh -i -c exit  1.84s user 1.29s system 103% cpu 3.013 total
zsh -i -c exit  1.90s user 1.32s system 103% cpu 3.119 total
zsh -i -c exit  1.96s user 1.37s system 103% cpu 3.199 total
zsh -i -c exit  1.92s user 1.30s system 104% cpu 3.092 total
zsh -i -c exit  2.04s user 1.49s system 102% cpu 3.445 total
zsh -i -c exit  1.90s user 1.34s system 103% cpu 3.140 total
zsh -i -c exit  1.90s user 1.29s system 103% cpu 3.073 total
zsh -i -c exit  2.23s user 1.53s system 91% cpu 4.109 total
zsh -i -c exit  2.35s user 1.91s system 84% cpu 5.025 total
zsh -i -c exit  2.01s user 1.53s system 101% cpu 3.493 total

zsh 起動 遅い」等でググるzprofなるものが提供されているとわかった。zshの起動が遅いのでなんとかしたい - Qiita に従って.zshenvの最初と.zshrcの最後に以下を付け足す。

# .zshenv
zmodload zsh/zprof && zprof
# .zshrc
if (which zprof > /dev/null 2>&1) ;then
  zprof
fi

すると起動時にプロファイル結果が出力される。長いので詳細は省略している。

num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    6        2320.87   386.81   68.33%    907.63   151.27   26.72%  pmodload
 2)    2         888.63   444.32   26.16%    888.32   444.16   26.16%  nvm_die_on_prefix
 3)    2        1916.71   958.35   56.44%    449.40   224.70   13.23%  nvm_auto
 4)    1         372.65   372.65   10.97%    372.25   372.25   10.96%  __kubectl_bash_source
 5)    4        1467.30   366.83   43.20%    356.07    89.02   10.48%  nvm
 6)    2         222.32   111.16    6.55%    198.99    99.50    5.86%  nvm_ensure_version_installed
 7)    1          74.28    74.28    2.19%     73.80    73.80    2.17%  _zsh_highlight_load_highlighters
 8)    2          29.95    14.97    0.88%     29.95    14.97    0.88%  compaudit
 9)    1          25.38    25.38    0.75%     25.38    25.38    0.75%  -zcache-hook-antigen
10)    2          23.32    11.66    0.69%     23.32    11.66    0.69%  nvm_is_version_installed
11)    2          16.74     8.37    0.49%     16.74     8.37    0.49%  nvm_supports_source_options
12)    2          41.45    20.73    1.22%     11.51     5.75    0.34%  compinit
13)   21          10.90     0.52    0.32%     10.90     0.52    0.32%  (anon)
14)    2           9.60     4.80    0.28%      9.60     4.80    0.28%  promptinit
15)    1           6.95     6.95    0.20%      6.95     6.95    0.20%  _zsh_highlight_bind_widgets
16)    1           4.06     4.06    0.12%      4.06     4.06    0.12%  async_init
17)    2           8.09     4.05    0.24%      2.22     1.11    0.07%  prompt_pure_setup
18)   12           1.79     0.15    0.05%      1.79     0.15    0.05%  add-zsh-hook
19)    2           5.55     2.77    0.16%      1.48     0.74    0.04%  async
20)    1           1.47     1.47    0.04%      1.47     1.47    0.04%  colors
21)    3           0.87     0.29    0.03%      0.87     0.29    0.03%  is-at-least
22)    1           0.78     0.78    0.02%      0.78     0.78    0.02%  -antigen-interactive-mode
23)    4           0.65     0.16    0.02%      0.65     0.16    0.02%  compdef
24)    4           0.59     0.15    0.02%      0.59     0.15    0.02%  nvm_has
25)    2        1933.81   966.91   56.94%      0.36     0.18    0.01%  nvm_process_parameters
26)    1           8.84     8.84    0.26%      0.20     0.20    0.01%  set_prompt
27)    4           0.19     0.05    0.01%      0.19     0.05    0.01%  -set-default
28)    1           5.57     5.57    0.16%      0.16     0.16    0.00%  -antigen-env-setup
29)    1           0.40     0.40    0.01%      0.15     0.15    0.00%  complete
30)    1           0.18     0.18    0.01%      0.12     0.12    0.00%  -zcache-antigen
31)    1          25.48    25.48    0.75%      0.10     0.10    0.00%  zcache-start
32)    2           0.23     0.12    0.01%      0.09     0.05    0.00%  -zcache-antigen-hook
33)    1           8.90     8.90    0.26%      0.06     0.06    0.00%  prompt
34)    1           0.04     0.04    0.00%      0.04     0.04    0.00%  bashcompinit
35)    1           0.04     0.04    0.00%      0.04     0.04    0.00%  is-callable
36)    2           0.03     0.02    0.00%      0.03     0.02    0.00%  nvm_is_zsh
37)    1           0.26     0.26    0.01%      0.03     0.03    0.00%  antigen
38)    1           0.06     0.06    0.00%      0.02     0.02    0.00%  antigen-bundle

nvm関連とpmodload関連の処理が重いとわかった。

nvm.sh を遅延ロードしてシェルの起動を高速化

NVM の nvm.sh を遅延ロードしてシェルの起動を高速化する - Qiita

↑の記事の対応をそのまま行ったところ、0.5~0.8秒ほどの改善が見られた。

❯ for i in $(seq 1 10); do time zsh -i -c exit; donezsh -i -c exit  1.46s user 1.01s system 99% cpu 2.480 total
zsh -i -c exit  1.42s user 0.95s system 100% cpu 2.364 total
zsh -i -c exit  1.42s user 0.96s system 100% cpu 2.372 total
zsh -i -c exit  1.43s user 0.97s system 98% cpu 2.431 total
zsh -i -c exit  1.44s user 0.97s system 95% cpu 2.539 total
zsh -i -c exit  1.46s user 0.98s system 100% cpu 2.429 total
zsh -i -c exit  1.38s user 0.97s system 103% cpu 2.278 total
zsh -i -c exit  1.38s user 0.95s system 103% cpu 2.242 total
zsh -i -c exit  1.40s user 0.93s system 104% cpu 2.223 total
zsh -i -c exit  1.41s user 0.91s system 104% cpu 2.219 total
num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    6        1738.74   289.79   81.14%    610.52   101.75   28.49%  pmodload
 2)    1         984.57   984.57   45.95%    401.19   401.19   18.72%  nvm_auto
 3)    1         362.83   362.83   16.93%    362.45   362.45   16.91%  __kubectl_bash_source
 4)    1         302.44   302.44   14.11%    302.29   302.29   14.11%  nvm_die_on_prefix
 5)    2         583.38   291.69   27.23%    170.47    85.23    7.96%  nvm
 6)    1         110.33   110.33    5.15%     97.92    97.92    4.57%  nvm_ensure_version_installed
 7)    1          69.76    69.76    3.26%     69.33    69.33    3.24%  _zsh_highlight_load_highlighters
 8)    1          29.12    29.12    1.36%     29.12    29.12    1.36%  -zcache-hook-antigen
 9)    2          28.16    14.08    1.31%     28.16    14.08    1.31%  compaudit
10)    1          12.41    12.41    0.58%     12.41    12.41    0.58%  nvm_is_version_installed
11)    2          40.29    20.14    1.88%     12.13     6.06    0.57%  compinit
12)   21          10.97     0.52    0.51%     10.97     0.52    0.51%  (anon)
13)    2           9.25     4.62    0.43%      9.25     4.62    0.43%  promptinit
14)    1           8.08     8.08    0.38%      8.08     8.08    0.38%  nvm_supports_source_options
15)    1           6.63     6.63    0.31%      6.63     6.63    0.31%  _zsh_highlight_bind_widgets
16)    1           3.20     3.20    0.15%      3.20     3.20    0.15%  async_init
17)   12           1.81     0.15    0.08%      1.81     0.15    0.08%  add-zsh-hook
18)    1           1.21     1.21    0.06%      1.21     1.21    0.06%  colors
19)    2           5.35     2.68    0.25%      1.02     0.51    0.05%  prompt_pure_setup
20)    3           0.81     0.27    0.04%      0.81     0.27    0.04%  is-at-least
21)    4           0.71     0.18    0.03%      0.71     0.18    0.03%  compdef
22)    2           3.90     1.95    0.18%      0.71     0.35    0.03%  async
23)    1           0.34     0.34    0.02%      0.34     0.34    0.02%  -antigen-interactive-mode
24)    2           0.30     0.15    0.01%      0.30     0.15    0.01%  nvm_has
25)    1         992.92   992.92   46.34%      0.27     0.27    0.01%  nvm_process_parameters
26)    4           0.21     0.05    0.01%      0.21     0.05    0.01%  -set-default
27)    1           6.11     6.11    0.29%      0.21     0.21    0.01%  set_prompt
28)    2           0.38     0.19    0.02%      0.18     0.09    0.01%  -zcache-antigen-hook
29)    1           6.42     6.42    0.30%      0.18     0.18    0.01%  -antigen-env-setup
30)    1           0.26     0.26    0.01%      0.16     0.16    0.01%  -zcache-antigen
31)    1          29.28    29.28    1.37%      0.16     0.16    0.01%  zcache-start
32)    1           0.38     0.38    0.02%      0.14     0.14    0.01%  complete
33)    1           0.43     0.43    0.02%      0.06     0.06    0.00%  antigen
34)    1           0.05     0.05    0.00%      0.05     0.05    0.00%  is-callable
35)    1           6.16     6.16    0.29%      0.05     0.05    0.00%  prompt
36)    1           0.04     0.04    0.00%      0.04     0.04    0.00%  bashcompinit
37)    1           0.09     0.09    0.00%      0.03     0.03    0.00%  antigen-bundle
38)    1           0.01     0.01    0.00%      0.01     0.01    0.00%  nvm_is_zsh

しかし見てみると、nvm関連の処理がまだまだ存在している… 奴はすでに葬ったはずでは…?

ここまでの変更は Lazy load nvm · ohbarye/dotfiles@5b0653b · GitHub である。

preztoのmodule読み込みで対象を減らした

プロファイラの結果をよくみると、nvm_autonvm_die_on_prefixといった処理はpmodloadから呼ばれているとわかった。

pmodloadが何をしているかというと、.zpreztorcの定義にしたがってpreztoのmoduleをloadする。名前そのままだ。

# .zpreztorc
zstyle ':prezto:load' pmodule \
  'environment' \
  ... # つづく

ここでloadしているmoduleにnodeがあったのでこれを消すと途端に速度が上がった。

この他にも使わないmoduleがないかを確認していき、ひとつずつ消していった結果のcommit: Do not load unused modules given by prezto · ohbarye/dotfiles@70fa79e · GitHub

各moduleが何をしているのかパッと見てはわからないので、https://github.com/sorin-ionescu/prezto/tree/master/modulesから一つずつ確認した。中には読んでもわからないものがあったので、一度そのmoduleを消してzshを再起動して普段と変わりなく操作できるかを確認したりもした。

大概はまったく使っていないaliasが使えなくなる程度なので大して困らなさそうだという気持ちでゴリゴリ消していった。一つmoduleを減らすたびにだいたい100~200 msec ほど高速化していったのでこれはやりがいがあった。

最終的な結果は以下:

❯ for i in $(seq 1 10); do time zsh -i -c exit; done
zsh -i -c exit  0.79s user 0.40s system 108% cpu 1.100 total
zsh -i -c exit  0.78s user 0.39s system 108% cpu 1.070 total
zsh -i -c exit  0.77s user 0.39s system 108% cpu 1.069 total
zsh -i -c exit  0.79s user 0.39s system 109% cpu 1.083 total
zsh -i -c exit  0.78s user 0.38s system 108% cpu 1.065 total
zsh -i -c exit  0.80s user 0.40s system 108% cpu 1.099 total
zsh -i -c exit  0.79s user 0.40s system 109% cpu 1.090 total
zsh -i -c exit  0.80s user 0.40s system 107% cpu 1.110 total
zsh -i -c exit  0.79s user 0.40s system 108% cpu 1.100 total
zsh -i -c exit  0.80s user 0.40s system 108% cpu 1.100 total
num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    1         363.84   363.84   54.43%    363.55   363.55   54.39%  __kubectl_bash_source
 2)    4         266.00    66.50   39.80%    135.32    33.83   20.24%  pmodload
 3)    1          73.05    73.05   10.93%     72.62    72.62   10.86%  _zsh_highlight_load_highlighters
 4)    2          27.63    13.82    4.13%     27.63    13.82    4.13%  compaudit
 5)    1          27.16    27.16    4.06%     27.16    27.16    4.06%  -zcache-hook-antigen
 6)    2          37.80    18.90    5.66%     10.17     5.08    1.52%  compinit
 7)    2           7.16     3.58    1.07%      7.16     3.58    1.07%  promptinit
 8)    1           7.06     7.06    1.06%      7.06     7.06    1.06%  _zsh_highlight_bind_widgets
 9)   14           6.48     0.46    0.97%      6.48     0.46    0.97%  (anon)
10)    1           3.63     3.63    0.54%      3.63     3.63    0.54%  async_init
11)   12           1.84     0.15    0.27%      1.84     0.15    0.27%  add-zsh-hook
12)    1           1.20     1.20    0.18%      1.20     1.20    0.18%  colors
13)    2           5.90     2.95    0.88%      1.06     0.53    0.16%  prompt_pure_setup
14)    3           0.90     0.30    0.13%      0.90     0.30    0.13%  is-at-least
15)    2           4.44     2.22    0.66%      0.81     0.40    0.12%  async
16)    1           0.30     0.30    0.05%      0.30     0.30    0.05%  -antigen-interactive-mode
17)    2           0.26     0.13    0.04%      0.26     0.13    0.04%  compdef
18)    1           6.68     6.68    1.00%      0.21     0.21    0.03%  set_prompt
19)    4           0.21     0.05    0.03%      0.21     0.05    0.03%  -set-default
20)    1           5.59     5.59    0.84%      0.19     0.19    0.03%  -antigen-env-setup
21)    1           0.29     0.29    0.04%      0.16     0.16    0.02%  complete
22)    1           0.20     0.20    0.03%      0.14     0.14    0.02%  -zcache-antigen
23)    2           0.25     0.13    0.04%      0.10     0.05    0.01%  -zcache-antigen-hook
24)    1          27.25    27.25    4.08%      0.09     0.09    0.01%  zcache-start
25)    1           6.73     6.73    1.01%      0.05     0.05    0.01%  prompt
26)    1           0.04     0.04    0.01%      0.04     0.04    0.01%  is-callable
27)    1           0.04     0.04    0.01%      0.04     0.04    0.01%  bashcompinit
28)    1           0.28     0.28    0.04%      0.03     0.03    0.00%  antigen
29)    1           0.06     0.06    0.01%      0.02     0.02    0.00%  antigen-bundle

次のボトルネック__kubectl_bash_source...なのだが、これはkubectlの補完を効かせるやつ (ここ)。最近はkubectlを触る機会があるのでこれを外すとそこそこ困るうえに代替案がパッと思いつかなかったので一旦放置。外すとようやく1秒未満で起動するようになるので補完機能も遅延で追加できたりしないかな。

環境

  • macOS 10.14.2
  • zsh 5.3 (x86_64-apple-darwin18.0)
  • prezto (versionの確認方法がわからないが、~/.antigen/repos/.zpreztoにcloneされたrepositoryのHEADはa338cba805f63f770e9078925bc5c46129e28bde)