💨

Neovim(Packer.nvim)で高速になっているかわからない高速化を施した話

2022/12/27に公開

はじめに

初めてzennにて記事を書きます
slackのvim-jpコミュニティでは現状観る専になっているため今後お話できればなぁとも考えているVimmerの端くれです
記事の内容自体は覚書程度の内容ですのでご容赦いただければと思います
始めにdotfileの場所を公開していおきます
https://github.com/SeitaHigashi/dotfiles
dotfiles自体は更新していますがリポジトリとしてのREADME.mdは更新していません

Neovimで高速になっているかわからない高速化を施した話

さて本題に入りましょう
まず始めに私の環境をご紹介します

OS: Manjaro Linux(i3 WM ver)
Host: MacBookPro12,1 
Shell: bash
Neovim: v0.9.0-dev-136-gfad558b6a (検証時)
Plugin Manager: Packer.nvim

上記の環境で今回の検証を行っています

そろそろ定年退職迎えても良さそうなPCですので悪しからず...

また、本来であれば検証であるので遅延ロード等を抜くべきなのですが今回はそのままの設定で検証しています予め御了承ください
以下が導入しているプラグインになります

Plugins
  • LuaSnip
  • SmoothCursor.nvim
  • cmp-buffer
  • cmp-cmdline
  • cmp-nvim-lsp
  • cmp-nvim-lua
  • cmp-path
  • cmp_luasnip
  • friendly-snippets
  • gitsigns.nvim
  • lsp_signature.nvim
  • lspkind-nvim
  • lspsaga.nvim
  • lualine-hybrid.nvim
  • lualine.nvim
  • mason-lspconfig.nvim
  • mason.nvim
  • neoterm
  • noice.nvim
  • nui.nvim
  • null-ls.nvim
  • nvim-autopairs
  • nvim-cmp
  • nvim-lspconfig
  • nvim-notify
  • nvim-web-devicons
  • packer.nvim
  • plenary.nvim
  • quick-scope
  • telescope-file-browser.nvim
  • telescope-packer.nvim
  • telescope-ui-select.nvim
  • telescope.nvim
  • trouble.nvim
  • vim-auto-save
  • vim-fugitive
  • vim-hybrid
  • vim-startuptime
  • vim-surround
  • vim-translator

前置きが長めになってしまいましたがPackerによるプラグイン管理において、プラグインのコンフィグが3行程度を超す際には別ファイルに記載するようにしています
例えば以下のように

.config/nvim
nvim
├── ginit.vim
├── init.lua
├── lua
│   ├── config
│   │   ├── gitsigns.lua
│   │   ├── lspsaga.lua
│   │   ├── lualine.lua
│   │   ├── mason-lspconfig.lua
│   │   ├── noice.lua
│   │   ├── null-ls.lua
│   │   ├── nvim-cmp.lua
│   │   ├── nvim-lsp-installer.lua
│   │   ├── nvim-notify.lua
│   │   ├── telescope.lua
│   │   ├── treesitter.lua
│   │   └── trouble.lua
│   ├── lsp-config
│   │   └── sumneko_lua.lua
│   ├── lsp-configs.lua
│   └── plugins.lua
└── plugin
   └── packer_compiled.lua

このようにコンフィグを別ファイルに分けているわけですが、以前の私は次のようにコンフィグを指定していました
例えばtelescope用コンフィグでは

plugins.lua(抜粋)
  use {
    'nvim-telescope/telescope.nvim',
    keys = '<Leader>',
    module_pattern = 'telescope',
    requires = {
      { 'nvim-telescope/telescope-file-browser.nvim', module = 'telescope._extensions.file_browser' },
      { 'nvim-telescope/telescope-packer.nvim', module = 'telescope._extensions.packer' },
      { 'nvim-telescope/telescope-ui-select.nvim', module = 'telescope._extensions.ui-select'},
    },
    config = function() require('config.telescope') end,
  }

configに関数としてrequireを指定しています
当然telescope用のコンフィグtelescope.luaにはベタ書きでコンフィグが記載されていますのでこちらで動作します
上記のように記載のあるinit.luaでstartuptimeを計測すると
5回加算平均で
70.6024msのロード時間がかかります

そんな中一つの記事を読んでいた際に気づいたのです
https://qiita.com/delphinus/items/fb905e452b2de72f1a0f

packer.nvimではコンフィグを一度コンパイルする必要があります
コンフィグ部分に関しては完全なコンパイルではないようですが
私の考えとしてはコンフィグの内容をpacker_compiled.luaに内包させることでファイルのサーチ時間が不要になり少しでも高速化できるのではないかというものです

手法としては比較的にかんたんです
まずはじめに更新前のpacker_compiled.luaをご紹介します

packer_compiled.lua(抜粋)
packer_compiled.lua
  ["telescope.nvim"] = {
   config = { "\27LJ\2\n0\0\0\3\0\2\0\0046\0\0\0'\2\1\0B\0\2\1K\0\1\0\21config.telescope\frequire\0" },
   keys = { { "", "<Leader>" } },
   loaded = false,
   needs_bufread = true,
   only_cond = false,
   path = "/home/seita/.local/share/nvim/site/pack/packer/opt/telescope.nvim",
   url = "https://github.com/nvim-telescope/telescope.nvim"
 },

こちらを見てわかるとおりpacker_compiled.luaではconfig内のfunctionが展開され、文字列として記載されているのです
つまり上記の文字列はrequest('config.telescope')のみを展開しているのです

そこで私は次のような処理を施しました
各コンフィグファイル先頭、末尾にreturn function(), endを追加したのです
そしてpackerのconfigはfunctionを使わずrequireで直接記載するのです

telescope.lua
return function ()
 vim.keymap.set('n', '<Leader>j', require('telescope.builtin').find_files, { noremap = true, silent = true })
 -- 省略
 end
plugins.lua
  use {
    'nvim-telescope/telescope.nvim',
    keys = '<Leader>',
    module_pattern = 'telescope',
    requires = {
      { 'nvim-telescope/telescope-file-browser.nvim', module = 'telescope._extensions.file_browser' },
      { 'nvim-telescope/telescope-packer.nvim', module = 'telescope._extensions.packer' },
      { 'nvim-telescope/telescope-ui-select.nvim', module = 'telescope._extensions.ui-select'},
      { 'xiyaowong/telescope-emoji.nvim', module = 'telescope._extensions.emoji'},
    },
    config = require('config.telescope'),
  }

このように変更します
するとpacker_compiled.luaは次のようになります

packer_compiled.lua
  ["telescope.nvim"] = {
    config = { "\27LJ\2\n*\0\0\2\0\3\0\0056\0\0\0009\0\1\0+\1\2\0=\1\2\0K\0\1\0\rreadonly\6o\bvimÂ\f\1\0\r\0Z\0³\0016\0\0\0009\0\1\0009\0\2\0'\2\3\0'\3\4\0006\4\5\0'\6\6\0B\4\2\0029\4\a\0045\5\b\0B\0\5\0016\0\0\0009\0\1\0009\0\2\0'\2\3\0'\3\t\0006\4\5\0'\6\6\0B\4\2\0029\4\n\0045\5\v\0B\0\5\0016\0\0\0009\0\1\0009\0\2\0'\2\3\0'\3\f\0006\4\5\0'\6\6\0B\4\2\0029\4\r\0045\5\14\0B\0\5\0016\0\0\0009\0\1\0009\0\2\0'\2\3\0'\3\15\0006\4\5\0'\6\6\0B\4\2\0029\4\16\0045\5\17\0B\0\5\0016\0\0\0009\0\1\0009\0\2\0'\2\3\0'\3\18\0006\4\5\0'\6\19\0B\4\2\0029\4\20\0049\4\21\0049\4\21\0045\5\22\0B\0\5\0016\0\5\0'\2\19\0B\0\2\0026\1\5\0'\3\23\0B\1\2\0026\2\5\0'\4\24\0B\2\2\0026\3\5\0'\5\25\0B\3\2\0029\3\26\3\18\4\3\0005\6\28\0003\a\27\0=\a\29\6B\4\2\0029\5\30\0005\a8\0005\b\31\0005\t/\0005\n!\0009\v \1=\v\"\n9\v#\1=\v$\n9\v%\1=\v&\n9\v'\1=\v(\n9\v'\1=\v)\n9\v*\1=\v+\n9\v,\1=\v-\n9\v%\0019\f\29\4 \v\f\v=\v.\n=\n0\t5\n1\0009\v \1=\v\"\n9\v#\1=\v$\n9\v%\1=\v2\n9\v%\1=\v&\n9\v'\1=\v3\n9\v'\1=\v(\n9\v*\1=\v4\n9\v*\1=\v+\n9\v,\1=\v5\n9\v,\1=\v-\n9\v%\0019\f\29\4 \v\f\v=\v6\n9\v%\0019\f\29\4 \v\f\v=\v.\n=\n\3\t=\t7\b=\b9\a5\b;\0005\t:\0=\t\r\b5\t<\0=\t=\b5\t>\0=\t?\b5\t@\0=\tA\b5\tB\0=\tC\b=\bD\a5\bU\0005\tT\0005\nS\0005\vF\0009\fE\2=\fG\v9\fH\2=\fI\v9\fJ\2=\fK\v9\fL\2=\fM\v9\fN\2=\f.\v9\fO\2=\fP\v9\fQ\2=\fR\v=\v0\n=\n7\t=\t\21\b=\b\20\aB\5\2\0019\5V\0'\a\21\0B\5\2\0019\5V\0'\aW\0B\5\2\0019\5V\0'\aX\0B\5\2\0019\5V\0'\aY\0B\5\2\1K\0\1\0\nemoji\14ui-select\vpacker\19load_extension\1\0\0\1\0\0\1\0\0\6.\18toggle_hidden\6~\rgoto_cwd\tcopy\6D\vremove\6R\vrename\6N\vcreate\6H\1\0\0\20goto_parent_dir\fpickers\21lsp_code_actions\1\0\1\17initial_mode\vnormal\24lsp_implementations\1\0\1\17initial_mode\vnormal\19lsp_references\1\0\1\17initial_mode\vnormal\20lsp_definitions\1\0\1\17initial_mode\vnormal\1\0\0\1\0\1\17initial_mode\vnormal\rdefaults\1\0\0\rmappings\6p\6s\6v\6q\6l\1\0\0\6i\1\0\0\6P\6S\15file_split\6V\16file_vsplit\n<esc>\6Q\nclose\6L\19select_default\6K\28move_selection_previous\6J\1\0\0\24move_selection_next\1\0\1\20layout_strategy\rvertical\nsetup\rreadonly\1\0\0\0\18transform_mod\25telescope.actions.mt/telescope._extensions.file_browser.actions\22telescope.actions\1\0\2\vsilent\2\fnoremap\2\17file_browser\15extensions\14telescope\14<Leader>f\1\0\2\vsilent\2\fnoremap\2\fkeymaps\14<Leader>h\1\0\2\vsilent\2\fnoremap\2\fbuffers\14<Leader>d\1\0\2\vsilent\2\fnoremap\2\14live_grep\14<Leader>k\1\0\2\vsilent\2\fnoremap\2\15find_files\22telescope.builtin\frequire\14<Leader>j\6n\bset\vkeymap\bvim\0" },
    keys = { { "", "<Leader>" } },

とても長いです
変更の効果を感じます

時間の計測に入ります
その処理内容を施したもののstartuptimeは
69.0314msとなります

プラグインなし(-u NONE)でのロード時間が
7.3908msとなりましたので
効果に関しては次の式で求めます

\cfrac{( before - none ) - ( after - none )}{( before - none )} = 0.024853

よって2.5%の速度向上効果が見られます 意味ないですね

さいごに

今回は簡単に高速化できる手段を試してみました
私は遅延読み込みを使った状態で検証していますのであまり良い結果を得られませんでしたが遅延読み込みを使用しないのであればある程度効果はあるのではないかと思います(遅延読み込みを使用しないのであればそもそも読み込みの高速化を考えないほうがいい気もしますが…)
ぜひ活用いただければと思います

Discussion