emahiro/b.log

Drastically Repeat Yourself !!!!

Prezto をやめて sheldon に移行して zsh の起動速度を改善してみた

これはなに?

zshプラグインマネージャーとして Prezito を使っていましたがこれをやめて sheldon に移行したログです。

sheldon とは?

Rust 製のシェルのプラグインマネージャー。
Rust 製だけあってそもそも高速です。

brew でインストールできますが cargo でインストールできるのもいいですね。

ドキュメントも丁寧にまとめっていて良きです。

sheldon.cli.rs

動機

zsh の起動に大体 600ms 程度かかっていたのがだいぶ気になってはいたものの、高速化するのもだいぶ手間だな〜とか思っていたときに以下のエントリを読んだのがきっかけです。

karamaru-alpha.com

実際にはここで紹介されているうちの1つ(sheldon の採用)のみしか行っていませんが、体感でもだいぶ早くなりました。

やったこと

  1. prezto を削除して sheldon を入れる。
  2. zsh-defer をいれて遅延ロード処理を追加。
  3. sheldon source 読み込み結果をキャッシュする。
  4. zshrc の設定を更新する。

これらはすべて参考にしたサイトに記載されていた内容と 公式の Docs を参考にして進めました。

結果

sheldon 周りの設定を置き換えたのみの Before/After はこんな感じでした。

# before
zsh -i -c exit 
0.11s user 0.15s system 59% cpu 0.635 total

# after
time zsh -i -c exit
zsh -i -c exit  0.07s user 0.13s system 52% cpu 0.377 total

大体 600~700ms かかっていたのが 300~400ms まで改善しました。

元記事では 20ms まで落とせたらしいですがそこまでは行きませんでした。もっと早くできそうな気もしないでもないですが、zshrc で eval $(...env init -) というやってる処理が重たく、この辺はもう少し改善の余地がありそうだなと思いました。

というのも zsh の plugin 読み込みが遅いのかなと思っていたんですが、そこだけ切り取ると 30ms 程度で終わっていたので zshrc の読み込みに時間がかかってそう、というところに気がついたのがきっかけです。

time sheldon source
source "/Users/hiromichiema/.local/share/sheldon/repos/github.com/romkatv/zsh-defer/zsh-defer.plugin.zsh"
zsh-defer source "/Users/hiromichiema/.local/share/sheldon/repos/github.com/zsh-users/zsh-autosuggestions/zsh-autosuggestions.zsh"
zsh-defer source "/Users/hiromichiema/.local/share/sheldon/repos/github.com/zsh-users/zsh-syntax-highlighting/zsh-syntax-highlighting.plugin.zsh"
sheldon source  0.01s user 0.01s system 60% cpu 0.027 total

ちなみに rbenv とかそのへんを削除してみたら 100ms 弱早くなったのでやっぱり zshrc の読み込みもある程度少なくしておく必要がありそうで、試しにいつ設定したか忘れていた pyenv の設定をまるっと削除したら 100ms 以下まで起動を高速化できました。
env 系の読み込み処理を入れてる場合は遅延実行や断捨離を検討してみてもいいかもしれません。

time zsh -i -c exit
zsh -i -c exit  0.02s user 0.03s system 76% cpu 0.077 total

はまったところ

github からの プラグインを DL を指定するときは ssh でデフォルト設定していないと Git の認証で落ちる。

.ssh/id_rsa を使っていないとこのエラーが発火します。 これの回避のためには .gitconfig にて sshCommand を指定する必要があります。以下のような設定を追記します。

[core]
    sshCommand = "ssh -i /path/to/your/private/key"

特に GitHub に登録している鍵をデフォルトの id_rsa とは別で分けてるケースで必要になります。
これに引っかかると sheldon source で設定を更新しても反映されず、 GitHub の認証で落ちるエラーが出力されます。

remote (https 経由)でプラグインを DL するときは raw の URL を指定しないといけない

これも結構ハマりました。GitHub を指定しないときは remote で repository の URL (正確には *.plugin.zsh のファイルまで)を指定すると HTTP 経由でプラグインを clone してくれるのですが、URL は GitHub のURL ではなく、raw の URL が必要でした。
これは issue にも起票してありましたけど結構罠でした。

zsh-defer を使う場合には zsh-defer を最初に読み込む

言われると当たり前ですが遅延読み込みをする場合には遅延読み込みをするライブラリを先に読み込んで後続のライブラリを遅延読み込み行う事が必要です。

shell = "zsh"
apply = ["defer"]

[templates]
defer = "{% for file in files %}zsh-defer source \"{{ file }}\"\n{% endfor %}"

[plugins.zsh-defer]
github = "romkatv/zsh-defer"
apply = ["source"]

上記のように apply=["defer"] を使う場合には zsh-defer を先に読み込んでおきます。

参考にしたサイト

zenn.dev

zenn.dev

zenn.dev

zenn.dev

github.com

github.com