记一次 vim debug - 解决 vim 执行命令时间过长


使用 vim-plug 执行 PlugClean 的时候,CPU 都会飙升,而且执行需要 >10s,尝试解决。

TL;DR:vim 自带的列举文件函数 globpath 效率远低于命令 find 又低于 fd ,替换即可。

https://github.com/oldkingOK/vim-plug/commit/dcd710d99c53b75bd9b0f01eaa9ce71ed3117d8e

找了半天,才发现 vim 自带了一个 profile 的命令,用于测量脚本执行的时间。

:profile start vim_profile.log
:profile func *
" profile 所有的 func

然后开始执行需要 profile 的命令,这里是 :PlugClean

:profile stop

查看 ~/.vim/autoload/plug.vimPlugClean 会执行 s:clean 函数。在结果中搜索即可

可以看到,两个耗时最长的函数均为 s:glob_dir 。在最下面也有耗时排名:

猜测 self 就是本身消耗的时间,total 就是包括调用其他函数的时间。这里耗时最长的 4_glob

FUNCTION  <SNR>4_glob()
    Defined: ~/.vim/autoload/plug.vim:265
Called 16 times
Total time:  11.927213987
 Self time:  11.458387360

count     total (s)      self (s)
   16  11.927171176  11.458344549   return s:lines(globpath(a:from, a:pattern))

查阅之后,globpath 就是遍历文件,例如 globpath('.', '*') 就是遍历当前文件夹下的所有文件,如果是 ** ,那就是递归遍历。所以这里的问题是,层数太多了,在查找 YouCompleteMe 的时候,因为 YCM 会把所有的依赖都放进自己的插件文件夹,比如 Go Binaries,clangd 所需要的头文件等等,就会爆炸。

这里尝试使用 find 来限制层数。即 system('find '.a:from.' -maxdepth 10 -name "'.a:pattern.'"'),不出所料,时间大幅降低!

偶然发现,就算是不限制层数,find 也比 globpath 快。这里追求更快,使用 Rust 写的 fd ,即最终的方案。

 

 


运行时间 427 天 | 总访问量