普段 vimrc をちょこちょこいじることはあっても zshrc をいじることってあんまりない。
変更する時は実行ファイルがある場所にパスを通したり source <(kubectl completion zsh)
のように補完したり alias
設定したりするくらい。
ある時気が付いた。
俺の zsh 起動遅いのでは。。。。
普段は tmux 使っていてセッション作成したりペインを分割しては削除したりと zsh が起動する機会が多い。
ただ起動する時にちょっと待ちが発生していて、だんだんそれに耐えきれなくなった。
計測
まずはどれくらい時間がかかっているか計測してみる。
$ for i in {1..10} ; do time ( zsh -i -c exit ); done ( zsh -i -c exit; ) 0.91s user 0.58s system 102% cpu 1.463 total ( zsh -i -c exit; ) 0.92s user 0.58s system 107% cpu 1.394 total ( zsh -i -c exit; ) 0.92s user 0.56s system 108% cpu 1.356 total ( zsh -i -c exit; ) 0.94s user 0.57s system 109% cpu 1.379 total ( zsh -i -c exit; ) 1.02s user 0.59s system 105% cpu 1.536 total ( zsh -i -c exit; ) 0.96s user 0.62s system 103% cpu 1.522 total ( zsh -i -c exit; ) 0.91s user 0.58s system 105% cpu 1.416 total ( zsh -i -c exit; ) 1.04s user 0.58s system 105% cpu 1.541 total ( zsh -i -c exit; ) 0.94s user 0.62s system 107% cpu 1.458 total ( zsh -i -c exit; ) 0.97s user 0.61s system 106% cpu 1.471 total
だいたい1秒ちょいかかっている。
毎回セッション作成したりタブ開いたりした時に1秒ちょいかかるのは地味に辛い。
どこがボトルネックになってるのか確認
zsh には zprof
というプロファイルをとるためのツールが用意されいるのでこれを使う。
使い方としては
~/.zshenv
の一番はじめにzmodload zsh/zprof && zprof
を追加~/.zshrc
の一番最後に次のコマンドを追加する
if (which zprof > /dev/null 2>&1) ;then zprof | less fi
あとはタブとか開いて zsh を起動するだけ。
num calls time self name ----------------------------------------------------------------------------------- 1) 1 143.73 143.73 33.30% 143.73 143.73 33.30% goenv 2) 1 86.60 86.60 20.06% 86.28 86.28 19.99% __kubectl_bash_source 3) 4 84.72 21.18 19.63% 84.72 21.18 19.63% compaudit 4) 3 73.20 24.40 16.96% 33.58 11.19 7.78% pmodload 5) 1 32.21 32.21 7.46% 31.93 31.93 7.40% __helm_bash_source 6) 3 103.85 34.62 24.06% 19.13 6.38 4.43% compinit 7) 2 13.23 6.61 3.06% 13.23 6.61 3.06% promptinit 8) 2 12.60 6.30 2.92% 5.58 2.79 1.29% prompt_sorin_setup 9) 1 5.37 5.37 1.24% 5.37 5.37 1.24% async_init 10) 10 2.10 0.21 0.49% 2.10 0.21 0.49% (anon) 11) 9 2.00 0.22 0.46% 2.00 0.22 0.46% add-zsh-hook 12) 2 6.65 3.33 1.54% 1.28 0.64 0.30% async 13) 2 0.84 0.42 0.19% 0.84 0.42 0.19% is-at-least 14) 1 14.21 14.21 3.29% 0.53 0.53 0.12% set_prompt 15) 3 0.43 0.14 0.10% 0.43 0.14 0.10% compdef 16) 3 0.82 0.27 0.19% 0.39 0.13 0.09% complete 17) 1 14.56 14.56 3.37% 0.34 0.34 0.08% prompt 18) 3 0.12 0.04 0.03% 0.12 0.04 0.03% bashcompinit 19) 1 0.06 0.06 0.01% 0.06 0.06 0.01% is-callable
これから分かったこととしては
- goenv が一番時間かかってる
eval "$(goenv init -)"
してるとこかな
- 補完系の compinit が時間かかってる
- __kubectl_bash_source もたぶん補完のやつ
ということで今回は rbenv init -
とか goenv init -
とかの *env を init してる部分と source <(kubectl completion zsh)
とかでコマンドの補完が効くようにしている部分を改善する。
改善方針
今回対象になったコマンドはどれも毎回?使うわけではない。
例えば source <(kubectl completion zsh)
の補完系の処理は kubectl
を使う時しか使わない。
そこで遅延して読み込めないかと考える。
zplugというzshというプラグインマネージャーがあってこれが lazy
というオプションを提供しており、これを使うことで遅延して読み込めそう。
github.com
ただ元々 zplug 使っていただけではないし、このために入れるのもなんか違う気がしたので別の方法を考えてみた。
実際にやったこと
今回は次のような関数を定義することで初回起動を高速化した。
例えば kubectl の場合は↓を .zshrc
に追加する。
kubectl() { unfunction "$0" source <(kubectl completion zsh) $0 "$@" }
kubectl というコマンドを定義している。
いつものように kubectl logs
をするとこの関数が呼ばれる。
実際には関数の最後で $0 "$@"
しているのでちゃんと動作はする。
補完の source <(kubectl completion zsh)
も実行している。
しかし毎回コマンドを実行するたびに source
を実行するのは微妙。。。
そこでこの関数の一番のポイントが unfunction "$0"
!!
これを実行することで今回定義した kubectl 関数を破棄してくれるので、2度目に実行する時はいつもの kubectl を実行してくれる。
これを rbenv init -
とか遅そうなところに適用していく。
注意点としては rbenv init -
をコマンドラインで実行するとわかるけど、shims
への PATH
の export とかしているので、これは .zshrc
にベタ書きする必要がある。
これをしないと rbenv でいれた ruby が使えなくなってしまう。
どれくらい早くなったのか
for i in {1..10} ; do time ( zsh -i -c exit ); done ( zsh -i -c exit; ) 0.08s user 0.06s system 96% cpu 0.147 total ( zsh -i -c exit; ) 0.08s user 0.06s system 97% cpu 0.140 total ( zsh -i -c exit; ) 0.08s user 0.06s system 96% cpu 0.151 total ( zsh -i -c exit; ) 0.08s user 0.06s system 98% cpu 0.142 total ( zsh -i -c exit; ) 0.08s user 0.06s system 98% cpu 0.139 total ( zsh -i -c exit; ) 0.10s user 0.08s system 96% cpu 0.185 total ( zsh -i -c exit; ) 0.08s user 0.06s system 97% cpu 0.149 total ( zsh -i -c exit; ) 0.08s user 0.05s system 96% cpu 0.139 total ( zsh -i -c exit; ) 0.09s user 0.06s system 97% cpu 0.149 total ( zsh -i -c exit; ) 0.08s user 0.06s system 97% cpu 0.138 total
0.15くらい!!!!! めっちゃ早くなった
最後に
今回は遅くなった zsh の起動を計測して改善してみました。
もっと良い方法があれば教えてください!!!