関連記事
TL;DR
速さを求めるならZpluginを使おう
はじめに
普段もっとも良く使うアプリケーションであるシェルにおいて、なにが一番大事だろうか?
見た目?操作性?拡張性?
いや違う,速さだ1。
特に起動時の速さが重要だ。
たとえば、起動に1秒かかるシェルと0.1秒で起動出来るシェルがあったとする。
1回の起動あたりに900ms差が出る。
1日にシェルを最低100回起動するので2、
$$
\frac{0.9 \cdot 100 \cdot 365}{60\cdot60} \simeq 9 ; \text{hours}
$$
なんということだ、1年で9時間も差が出てしまった。
人生を浪費にしないためにも、一刻でも早くシェルの起動を高速化しなければならないことが分かったと思う3。
高速化における課題
素のZshの起動は高速だ。
遅くなる原因は設定やプラグインのせいだ。
しかし、あの便利さを経験してしまったら、プラグインなしのカスタマイズされていないZshは流石にたえられない。
そこで、利便性を維持したまま、高速化を行なうために必要なのは以下の2点である。
- 必要な設定やプラグインのみ残し、余計な設定の排除
- プラグインの読み込み速度の高速化
本稿では2点めの問題を解決するために、既存のプラグインマネージャの起動・読み込み速度について比較した。
プラグインマネージャー
このサイトに載っているのだけでも沢山のマネージャ・フレームワークが存在するので、そのすべて試すのは難しい(てかやりたくない)。
そこで、高速性を謳っていそうなプラグインマネージャにだけに絞って比較した。
今回比較したプラグインマネージャの2/6時点での情報を表にまとめた。
他にも速そうなものがあったら追加する。
プラグインマネージャ | star数 | 最終更新日(master) |
---|---|---|
zplug | 2,873 | Jul 4, 2018 |
zgen | 1,004 | Oct 21, 2018 |
antibody | 821 | Jan 24, 2019 |
zplugin | 259 | Feb 4, 2019 |
zr | 51 | Jan 30, 2019 |
測定方法
起動速度を測定するためにhyperfineというベンチマークコマンドを使用した。
hyperfine --max-runs 15 \
--warmup 3 \
--export-json result/$1.json \
"zsh -d -f -l -c 'source plugin.zsh; exit'"
--max-runs
が試行回数で、コマンドの実行にかかった時間の平均・標準偏差・最大値・最小値を測ってくれる。
zshの起動はI/Oやプラグインマネージャのキャッシュの影響で初回と2回目以降で速度が変わってしまうので--warmup
で実際の測定前に複数回(3回)事前にコマンドを実行しおく。
zsh -d -f -l -c 'source plugin.zsh; exit'
で、コンフィグをロードせずにZshを立ち上げ、プラグイン関係のスクリプトをロードしてから終了するまでの時間を計測した。
ちなみに自分はlinux OSで試している。違うOSだと違う結果になるかもしれない。
測定設定
測定する時は読み込むプラグインの数で場合分けした。
- プラグイン0個
2. プラグインマネージャによっては内部でcompinitを行っているものあるので、合わせるためにそれだけは行っておく - 普段使っているプラグイン10個
最初の設定では、プラグインマネージャのオーバーヘッドを測り、2つ目で総合的な速度を測定する。
プラグイン数が少ないない人は前者を、多くのプラグインを使う人は後者を参考にしたらいいと思う。
プラグインマネージャ
実際に測定に使ったスクリプトを載せておく。
自分は各プラグインマネージャについてはチュートリアルを見たぐらいなので、「より高速な方法があるぞ」という場合は教えて欲しい。
zplug
プラグイン0個
source ~/.zplug/init.zsh
if ! zplug check; then
install
fi
zplug load
プラグイン10個
起動時にはいらないプラグインについては遅延読み込みを行なう。
source ~/.zplug/init.zsh
zplug "zsh-users/zsh-completions"
zplug "zsh-users/zsh-autosuggestions"
zplug "zsh-users/zsh-syntax-highlighting", defer:2, lazy:true
#
zplug "mafredri/zsh-async"
zplug "sindresorhus/pure"
zplug "marzocchi/zsh-notify", if:"has 'terminal-notifier' || has 'notify-send'"
zplug "b4b4r07/enhancd", use:"init.sh", lazy:true
zplug "vintersnow/anyframe", lazy:true
zplug "lukechilds/zsh-nvm", lazy:true, as:command
zplug "greymd/tmux-xpanes", lazy:true, as:command
zplug 'zplug/zplug', hook-build:'zplug --self-manage'
if ! zplug check; then
zplug install
fi
zplug load
zgen
プラグイン0個
source "${HOME}/.zgen/zgen.zsh"
if ! zgen saved; then
zgen save
fi
プラグイン10個
遅延読み込みはない?
source "${HOME}/.zgen/zgen.zsh"
if ! zgen saved; then
zgen load "zsh-users/zsh-completions" src
zgen load "zsh-users/zsh-autosuggestions"
zgen load "mafredri/zsh-async"
zgen load "sindresorhus/pure"
zgen load "marzocchi/zsh-notify"
zgen load "vintersnow/anyframe"
zgen load "b4b4r07/enhancd"
zgen load "lukechilds/zsh-nvm"
zgen load "greymd/tmux-xpanes"
zgen load "zsh-users/zsh-syntax-highlighting"
zgen save
fi
antibody
antibodyはまず、プラグインのインストールなどをzshrcでは管理せず、コマンドで実行することで読み込みスクリプトを自動生成して(antibody_bundle.zsh
)、それをzshrcで読み込む形をとる。
遅延読み込みを行なう方法はない?
プラグイン0個
autoload -Uz compinit; compinit -iCd $HOME/.zcompdump
プラグイン10個
source antibody_bundle.zsh
autoload -Uz compinit; compinit -iCd $HOME/.zcompdump
zplugin
プラグイン0個
### Added by Zplugin's installer
source '/home/vinter/.zplugin/bin/zplugin.zsh'
autoload -Uz _zplugin
(( ${+_comps} )) && _comps[zplugin]=_zplugin
### End of Zplugin's installer chunk
# compinitの代わりが用意されていた
zpcompinit
プラグイン10個
いろいろオプションがあってどうするべきなのかよく分からない。
ここを参考にセットアップ
### Added by Zplugin's installer
source '/home/vinter/.zplugin/bin/zplugin.zsh'
autoload -Uz _zplugin
(( ${+_comps} )) && _comps[zplugin]=_zplugin
### End of Zplugin's installer chunk
zplugin light "zsh-users/zsh-completions"
zplugin ice wait"!0" atload"_zsh_autosuggest_start"
zplugin light "zsh-users/zsh-autosuggestions"
zplugin light "mafredri/zsh-async"
zplugin light "sindresorhus/pure"
zplugin light "marzocchi/zsh-notify"
zplugin ice wait'!0'; zplugin light "vintersnow/anyframe"
zplugin ice wait'!0'; zplugin light "b4b4r07/enhancd"
zplugin ice wait'!0'; zplugin light "lukechilds/zsh-nvm"
zplugin ice wait'!0'; zplugin light "greymd/tmux-xpanes"
zplugin ice wait"!0" atinit"zpcompinit; zpcdreplay"
zplugin light "zsh-users/zsh-syntax-highlighting"
zr
これもantibody同様にロードファイルを作っているだけ
プラグイン0個
autoload -Uz compinit; compinit -iCd $HOME/.zcompdump
プラグイン10個
if [[ ! -f ~/.zr/init.zsh ]]; then
zr load \
zsh-users/zsh-completions \
zsh-users/zsh-autosuggestions \
zsh-users/zsh-syntax-highlighting \
mafredri/zsh-async \
sindresorhus/pure \
marzocchi/zsh-notify \
vintersnow/anyframe \
b4b4r07/enhancd \
lukechilds/zsh-nvm \
greymd/tmux-xpanes
fi
source ~/.zr/init.zsh
結果
0 plugin
の時はantibodyとzrはcompinitをしているだけなので最速だ。zgenやzplugはロード時にいろいろやっているのか遅い。
zpluginは本体をロードしているわりにはほぼオーバーヘッドがない。
一方で10 plugin
では、顕著な差が出た。
zgenはほぼ速度が変わっていないのでかなり優秀なのだが、zplugin、お前0 plugin
の時と比べて速くなっていないか(43ms → 32ms)?
zpluginで読み込みを行った時のプロファイルを見ると
num calls time self name
-----------------------------------------------------------------------------------
num calls time self name
-----------------------------------------------------------------------------------
1) 1 11.83 11.83 36.78% 11.83 11.83 36.78% prompt_pure_state_setup
2) 4 24.34 6.08 75.63% 4.98 1.25 15.48% -zplg-load-plugin
3) 10 2.59 0.26 8.05% 2.33 0.23 7.24% --zplg-shadow-autoload
4) 5 2.81 0.56 8.75% 2.08 0.42 6.46% add-zsh-hook
5) 16 29.36 1.83 91.25% 1.77 0.11 5.51% zplugin
6) 2 1.64 0.82 5.09% 1.64 0.82 5.09% async_init
7) 4 26.79 6.70 83.25% 1.37 0.34 4.26% -zplg-load
8) 1 1.16 1.16 3.62% 1.16 1.16 3.62% is-at-least
9) 4 0.60 0.15 1.86% 0.60 0.15 1.86% -zplg-register-plugin
10) 4 0.53 0.13 1.65% 0.53 0.13 1.65% -zplg-shadow-off
11) 1 15.21 15.21 47.28% 0.45 0.45 1.41% prompt_pure_setup
-zplg-load-plugin
の呼び出し回数が4回でこれが遅延読み込みをしていないプラグインの読み込みのようだ。そしてzplugin全体で29msしか使用していないので、ほかのと比べてオーバーヘッドがかなり小さい。
結構な時間を喰うcompinitが出てきていのには驚く。これ遅延読み込み出来たんかい!
一応欠点としては、wait ice
などturbo modeを使うにはZsh 5.3以上でないと行けないようだ
おわりに
zpluginを使おう。
感想
zpluginが良いらしいと聞いて比較してみたくて始めたので、かなりzpluginよりの評価になっていると思う。(zpluginだけ書き方を工夫したりしたので)
でも他のプラグインのドキュメントを見る感じ、より高速な読み込みは出来そうにないと思う。
「もっと良い書き方があるよ!」「このプラグインマネージャなんで試してないの?」みたいな指摘を待っている。
zpluginさんのreadmeを見る感じまだまだ設定出来るところがあるのでもう少し調べたい。
ローカルフィアルもZpluginで管理出来るようなので、zshrc全体をZpluginで管理すればかなり高速な起動が出来そうだ。
参考
- vintersnow/zsh_plugin_manager_speed
- 【zsh高速化】え~、そんなプラグインマネージャーがあるんだったらもっと早く教えてよ、と姉が怒り出した - Zplugin
- dotfilesをキレイキレイするついでに晒す