neocomplcache を高速化した話し

普段 neocomplcache を使ってるけど、Vim 起動直後の補完のポップアップがもの凄く遅くてストレスを感じていた。
AutoComplPop は起動直後でも凄く速いが、neocomplcache と比べて機能が少ない。
# 日本語の不具合だのは自分で直せる思う


現状 neocomplcache の方がユーザは多いだろうし速くなって損をする人は居ないので改良できないかなーと思った。
ただ遅いとだけ報告しても情報が少なくて改良しようにもしてくれないと判断したので勝手にボトルネックになっている箇所を探し始める事にした。


ボトルネックの調査はポップアップ開始の関数に reltime() で start と end を計測して秒数を計測するようにした。
具体的には以下のファイルの関数の開始直後と終了直前に埋め込むような形にした。
neocomplcache.vim/neocomplcache.vim at master · Shougo/neocomplcache.vim · GitHub


まず群を抜いて遅いと感じる所が次のようなパターンで発生した。

PythonPHPユニットテストようのファイルは QuickRun で実行するために python.unit のようなファイルタイプが複数ある形になってる。
これはファイルタイプを python.unit, python, unit とファイルタイプを分割して補完候補を取得する。


原因は分かったので Issue として登録して、改善案を Pull Request して取り込んで貰った。
Add g:neocomplcache_ignore_composite_filetype_lists option by heavenshell · Pull Request #197 · Shougo/neocomplcache.vim · GitHub
ファイルタイプを python.unit とか書いているような人は以下のような設定を vimrc にすると速くなる。

let g:neocomplcache_ignore_composite_filetype_lists = {
  \ 'python.unit': 'python',
  \ 'php.unit': 'php',
  \}

これで 5.028276 sec 掛かってたのが大体 1.874612 sec まで速くなった。
ただしこれはファイルタイプが python と同じ位の速度。


次にどの補完候補を作成している時に遅いのか計測した。
neocomplcache.vim/cache.vim at master · Shougo/neocomplcache.vim · GitHub
ここを計測ポイントとして調査してみたところ、ファイルタイプが Python の場合 Pydiction(Python の辞書ファイル)の読み込みが遅かった。


ディスクからの読み込みが遅いのかと思って neocomplcache のキャッシュファイルを RAM Disk に置いてみた。
これはディスクが HDD の場合は効果があった。
自宅の MacBookPro は SSD に換装しているのであまり効果が無かったがそれでも 0.2sec 程度速くなった。


じゃあ実際に Vim Script のファイル読み込みが遅いのか計測してみた。

こんな感じで fileread だけを計測してみた。
ここがボトルネックになってると思ったけど意外に速かった。

builtin-readfile 0.020200 sec
vital-readfile 0.060254 sec


ソースコードを読んでみると、気になる点があった。
まずはロジック上不要と思われるループを回っている所があった。
コードの意図が良くわからなかったので質問したら不要との事でループは削除された。
- Improved check_cache_list(). · Shougo/neocomplcache.vim@b4b4a25 · GitHub


次に neocomplcache はキャッシュ用のファイルフォーマットを持っていて、それをポップアップに使うためにフォーマットしている所がある。

というような事をつぶやいていたら [twitter:@mattn_jp] さんにアドバイス頂いた。

自分でキャッシュファイルを VimSon(Vim Script)の形式をそのまま出してみようかと思ってたが、[twitter:@ShougoMatsu] さんに実装して頂いた。
早速実装されたので試してみた。
大分速くなった。


もっと速くならないかと色々調査している時にプラグインのドキュメントにある tags ファイルを読み込んでいるのに気付いた。
Pathogen を使っているので bundle 以下にあるプラグインの数分読み込んでいた。
vimrc で

set tags+=$HOME/.vim/tags/**3/tags;$HOME/.vim/tags/

と ; を指定していたため不要な tags を読み込んでいた。
これを ; 以降を削除すれば tags の読み込みを制御できた。


ただこれも呟いたら、neocomplcache 自体で読み込むのを止めて貰ったので最新のバージョンでは影響がない。
これで速度が 0.724542 sec まであがった。
素晴らしい。
職場の MacVim(Quad Core, メモリ 16GB) で試したら、0.458250 sec という数値まであがった。


最初は 5.028276 sec だったのが最終的に 0.724542 sec まで速度が改善された。
ファイルタイプが python でも 1 秒近く速くなった。
自宅の 4 年前の Mac なら起動直後はポップアップが以前よりストレス無く動作するようになった。
職場の速いマシンだとポップアップがちょっと引っかかるかなという程度であまり気にならなくなった。
vital.vim の readfile を使っている所を組み込みの readfile に変えたらもっと速くなると思うが、これは自分で少しやってみようかと思う。


「推測するな計測せよ」の言葉通り計測しながらやってみた所色々分かってよかった。
数値として見せる事で説得力が違う。
色々アドバイス頂いた [twitter:@mattn_jp] さん、実装&取り込んで頂いた [twitter:@ShougoMatsu] さん、ありがとうございます!!!!