LoginSignup
39
17

More than 5 years have passed since last update.

Vimのカーソル移動が重い原因をprofileする

Last updated at Posted at 2018-04-22

カーソル移動が遅かったのでprofileしてみた。

以下のような関数をvimrcに書く。

function! ProfileCursorMove() abort
  let profile_file = expand('~/log/vim-profile.log')
  if filereadable(profile_file)
    call delete(profile_file)
  endif

  normal! gg
  normal! zR

  execute 'profile start ' . profile_file
  profile func *
  profile file *

  augroup ProfileCursorMove
    autocmd!
    autocmd CursorHold <buffer> profile pause | q
  augroup END

  for i in range(100)
    call feedkeys('j')
  endfor
endfunction

profile_fileはプロファイルの結果がで出るファイル。~/logディレクトリは予め作っておく。

使い方は

$ vim +'call ProfileCursorMove()' <カーソルを動かすのが重いファイル>

上記コマンドを実行するとfeedkeys('j')によって、100回jが実行される。feedkeys()はキー実行を待たず、非同期で実行されるので、profile pause | qをすぐ下に書くと、キー実行が終わる前にvimが終了してしまう。そこで、CursorHoldを使い、カーソルが動かなくなったら終了するように書いた。

実行後にprofile_fileの下を見ると、各関数毎にかかった時間が書いてある。

FUNCTIONS SORTED ON TOTAL TIME
count  total (s)   self (s)  function
  306   0.106875   0.008378  fugitive#head()
  306   0.083811   0.018949  <SNR>37_repo_head()
  306   0.041424   0.033768  <SNR>37_repo_head_ref()
  612   0.027759             <SNR>37_repo()
  101   0.022314             <SNR>62_Highlight_Matching_Pair()
  306   0.010365             <SNR>37_sub()
  612   0.007656             <SNR>37_repo_dir()

ステータスラインにブランチ名を表示させるために使っているfugitive#head()が重い。

ステータスラインの表示にitchyny/lightline.vimを使っているが、そのREADMEを見るとブランチ名表示用にitchyny/vim-gitbranchというのがあるので試してみた。

FUNCTIONS SORTED ON TOTAL TIME
count  total (s)   self (s)  function
  306   0.046956             gitbranch#name()
  101   0.024812             <SNR>58_Highlight_Matching_Pair()
  204   0.005348             GetCurrentColumn()
  102   0.004285             lightline#link()

fugitive#head()に比べると倍くらい早いがまだ一番重い。Highlight_Matching_Pair()も結構重いが、これはitchyny/vim-parenmatchというプラグインを代わりに使うと、精度は多少落ちるが軽くなる1

ただし、このプラグインを使うとマッチした括弧のハイライトが下線になってしまうので、元と同じハイライトにするには、vimrcでcolorschemeを呼び出している箇所より後に

highlight link ParenMatch MatchParen

を書き、どこかに

let g:parenmatch_highlight = 0

を書く。

vim-parenmatchにした結果は、

FUNCTIONS SORTED ON TOTAL TIME
count  total (s)   self (s)  function
  306   0.045896             gitbranch#name()
  101   0.005845             parenmatch#update()
  204   0.005454             GetCurrentColumn()
  102   0.003950             lightline#link()
  306   0.002518             MyFileencoding()

parenmatch#update()のほうが大分早い。

しかし、カーソルを動かしてみるとまだまだ遅い。

'cursorline' を必要な時にだけ有効にする - 永遠に未完成の設定をやってみた。

めっちゃ早くなった。

設定前

$ time vim +'call ProfileCursorMove()' <カーソルを動かすのが重いファイル>
vim +'call ProfileCursorMove()'   6.03s user 4.06s system 96% cpu 10.496 total

設定後2

$ time vim +'call ProfileCursorMove()'  <カーソルを動かすのが重いファイル>
vim +'call ProfileCursorMove()'   1.30s user 0.54s system 91% cpu 2.015 total

よくよく考えると、関数で一番重いものでもトータルで0.1秒程度しか寄与してないので、関数は関係なかった。

ちなみにカーソル移動以外でかかっている時間は

$ time vim +'q'  <カーソルを動かすのが重いファイル>
vim +'q'   0.87s user 0.29s system 90% cpu 1.276 total

なので、カーソル移動には0.7秒くらいかかっているようだ。


  1. Vimの標準プラグインmatchparenが遅かったので8倍くらい速いプラグインを作りました - プログラムモグモグ: 作者による解説記事。 

  2. ただし、+commandで起動するとWinEnterのイベントが発生しないらしく、ブログではlet s:cursorline_lock = 0となっている箇所を0にした。 

39
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
17