Neovimの起動速度を改善した

コンテナで動かしているNeovimの起動速度を改善しました。

背景

M2 Macを購入してから、Neovimの起動速度が遅いことに気づきました。起動速度が遅いと作業効率が落ちて辛いため、改善することにしました。

起動速度の計測

まずは、現状の起動速度を計測しました。

nvimには--startuptimeオプションがあり、起動時間を計測することができます。

1$ nvim --startuptime ~/nvim.log +q

nvim.logを見ると、以下のように起動時間が記録されています。改善前は300ms程度かかっていました。

1times in msec
2 clock   self+sourced   self:  sourced script
3 clock   elapsed:              other lines
4
5~~省略~~

起動速度の改善

プラグインの読み込みを遅延させる

まずプラグインの読み込みを遅らせて、起動速度の改善を試みました。

下記はPacker.nvimを使ったプラグインの読み込み設定です。

 1vim.cmd [[packadd packer.nvim]]
 2
 3return require('packer').startup(function(use)
 4  -- Package manager
 5  use { 'wbthomason/packer.nvim', opt = true } -- Packerはコマンドを実行するときだけ利用するので、opt = trueにして必要なときだけ読み込む。
 6
 7  -- File manager
 8  use 'lambdalisue/fern.vim' -- 遅延させたくないものは素直に読み込む。
 9
10  -- 省略
11
12  -- Appearance
13  use {
14    'lukas-reineke/indent-blankline.nvim',
15    event = { 'BufRead', 'BufNewFile' }, -- バッファを読み込んだときに読み込む。
16  }
17
18  -- 省略
19
20  -- Auto completion
21  use {
22    'hrsh7th/nvim-cmp',
23    event = { 'InsertEnter' }, -- インサートモードに入ったときに読み込む。
24    requires = {
25      { 'hrsh7th/cmp-nvim-lsp', event = { 'InsertEnter' } },
26      { 'hrsh7th/vim-vsnip', event = { 'InsertEnter' } },
27    },
28    config = function() require('nvim_cmp') end,
29  }
30
31  -- 省略
32
33end)

次の点を考慮して、プラグインの読み込みを遅延させました。

  • packer.nvimはopt = trueを指定して、必要なときだけ読み込む。
  • プラグインの読み込みイベントをBufReadBufNewFileに設定して、バッファを読み込んだときに読み込む。
  • インサートモードに入ったときに読み込むプラグインは、InsertEnterイベントを指定して読み込む。

結果、起動速度は200ms程度に改善しました。

ARM64向けにビルドされたdockerイメージとNeovimを使う

プラグインのlazy loadingで30%程度の改善が見られましたが、まだ起動速度が遅いと感じたため、別の方法を試みました。

私はNeovimをUbuntuのコンテナ上で動かしているのですが、linux/amd64向けに用意されたdockerイメージを使っていました(エミュレートしてコンテナを動作させることになるので、動作は遅くなると推測)。

M2 MacはARM64向けのプロセッサを搭載しているため、ARM64用のdockerイメージを使い、さらにARM64用にビルドされたNeovimを使うことで、起動速度を改善できるのではないかと考えました。

dockerイメージのarm64対応

まず、使用しているdockerイメージがARM64に対応しているか確認しました。

ubuntuのdockerイメージはマルチアーキテクチャ対応となっており、ARM64のプラットフォームで動作することを確認できました。

arm64以外のプラットフォームでビルドする場合、–platformオプションを使うことでプラットフォームを指定できますが、ARM64の場合は指定しなくても動作することがわかりました。デフォルトでホスト側のプラットフォームに合わせて動作するようです。

1# docker-compose.yml
2services:
3  ubuntu:
4    platform: linux/arm64 # ←これが不要
5    image: ubuntu:latest

Neovimのarm64対応

次に、NeovimがARM64に対応しているか確認しました。残念ながら、公式のリリースページにはARM64用のバイナリが用意されていませんでした😞

いろいろ調べた結果、ソースコードからビルドすることでARM64用のバイナリを作成できることがわかりました。

下記、Neovimのビルド方法です。

1$ apt-get install ninja-build gettext cmake unzip curl build-essential
2$ git clone https://github.com/neovim/neovim
3$ cd neovim
4$ git checkout stable
5$ make CMAKE_BUILD_TYPE=RelWithDebInfo
6$ make install

ビルドが完了すると、/usr/local/bin/nvimにバイナリが作成されます。

結果

ARM64用のdockerイメージとNeovimを使うことで、起動速度が30ms以下に改善しました!やったね!🎉

 1times in msec
 2 clock   self+sourced   self:  sourced script
 3 clock   elapsed:              other lines
 4
 5000.007  000.007: --- NVIM STARTING ---
 6000.243  000.235: event init
 7000.356  000.113: early init
 8000.367  000.011: locale set
 9000.423  000.056: init first window
10000.730  000.307: inits 1
11000.748  000.017: window checked
12000.751  000.004: parsing arguments
13001.295  000.058  000.058: require('vim.shared')
14001.402  000.037  000.037: require('vim._options')
15001.404  000.106  000.068: require('vim._editor')
16001.405  000.220  000.057: require('vim._init_packages')
17001.407  000.436: init lua interpreter
18
19~~省略~~
20
21019.121  001.614: reading ShaDa
22019.299  000.178: opening buffers
23020.089  000.533  000.533: require('vim.version')
24022.511  003.067  002.534: sourcing /root/.local/share/nvim/site/pack/packer/start/copilot.vim/autoload/copilot.vim
25022.632  000.053  000.053: sourcing /root/.local/share/nvim/site/pack/packer/start/copilot.vim/autoload/copilot/util.vim
26022.666  000.247: BufEnter autocommands
27022.670  000.004: editing files in windows ←起動完了時間

まとめ

  • プラグインの読み込みを遅延させることで、起動速度を改善できた。
  • ARM64用のdockerイメージとNeovimを使うことで、起動速度を改善できた。

丸3日費やしましたが、GW中にNeovimの起動速度を改善できてよかったです😊

リポジトリ

参考