To fix the performance issue, ensure you have Rust installed on your system and run :call clap#helper#build_all() .
Introduction
The one selling point of vim-clap is in pure vimscript, having a good platform compatibility and minimal pain to set it up, which is apparently an advantage. However, it becomes a disadvantage when you do a large scale searching/filtering job for the limit of vimscript language.
Profile of async job at scale
For instance, using :Clap files from my home directory and input sr , the result is [791970/823172] . The following profile info is based on this commit dfffb5e.
Profile of NeoVim:
FUNCTIONS SORTED ON TOTAL TIME
count total (s) self (s) function
16737 2.416528 0.592996 <SNR>181_on_event()
16732 1.816953 0.267504 <SNR>181_append_output()
16731 1.505205 0.146196 <SNR>181_set_matches_count()
16732 1.379571 0.310434 clap#impl#refresh_matches_count()
16732 0.821710 0.141712 clap#indicator#set_matches()
16732 0.679998 0.317742 <SNR>183_apply_indicator()
3 0.492807 0.472198 <SNR>172_on_event()
16732 0.362257 0.177423 <SNR>183_padding()
16733 0.247077 0.140285 clap#sign#reset_to_first_line()
8 0.195782 provider#python3#Call()
16740 0.184996 0.100084 16()
5 0.147412 UltiSnips#TrackChange()
16732 0.106776 <SNR>184_sign_of_first_line()
16740 0.084913 clap#util#nvim_buf_get_first_line()
3 0.078762 0.000110 clap#handler#on_typed()
2 0.078562 0.003062 41()
2 0.075139 0.000245 clap#impl#on_typed()
5 0.067303 0.000438 clap#rooter#run()
2 0.063340 0.004730 <SNR>179_on_typed_async_impl()
2 0.052697 0.000056 clap#dispatcher#job_start()
Profile of Vim:
FUNCTIONS SORTED ON TOTAL TIME
count total (s) self (s) function
1613221 70.847359 38.246657 <SNR>172_out_cb()
1613224 31.405335 18.249628 clap#job#vim8_job_id_of()
1613229 13.155912 clap#job#parse_vim8_job_id()
791899 1.191679 <SNR>172_handle_cache()
1 0.537275 0.517298 <SNR>167_close_cb()
61 0.183191 0.007911 ElelineGitBranch()
60 0.170001 0.154896 FugitiveExtractGitDir()
18 0.021677 0.001292 <SNR>162_popup_filter()
2 0.020385 0.000444 142()
3 0.020079 0.019061 clap#impl#refresh_matches_count()
1 0.019937 0.000054 <SNR>167_on_complete()
2 0.019428 0.000085 <SNR>162_apply_input()
2 0.019320 0.001760 117()
5 0.018673 0.001056 clap#rooter#run()
2 0.016882 0.000210 clap#impl#on_typed()
10 0.014478 0.003716 traces#init()
2 0.014044 0.000092 <SNR>172_post_check()
2 0.013604 0.000199 <SNR>172_on_exit_common()
2 0.013177 0.000034 clap#impl#add_highlight_for_fuzzy_indices()
2 0.013143 0.010832 <SNR>170_apply_add_highlight()
For the result set having about 1M items, neovim is still tolerable if you seldom run into that case, but for vim it's totally unusable. The core idea of vim-clap is to spawn a new job on your typing and then react on the callback, the callback of the job is called too many times on the surface.
Related providers
The performance issue only happens to these providers that can have a huge result set.
Searching
Filtering
The current strategy is to use the built-in fzy written in python running synchronously when the items are no more than 10,000, switching the async way if it's more than the threshold and then it meets the same callback issue.
:Clap blines
:Clap lines
:Clap bcommits
:Clap commits
The challenge is to make clap#filter#() fast enough even when candidates is terrific.
|
function! clap#filter#(query, candidates) abort |
Possible solution
-
python multi thread. Since we have introduced the optional dependency for the built-in fzy support, we could also use the thread of python to improve the performance as suggested in #75 (comment). As I'm not a python expert, I'm not sure if this will land in vim-clap eventually.
-
lua . Could be faster than vimscript at least in some filtering cases. I observe something promissing based on the this script measuring the vimscript with the other script languages:
-
Boost python filtering using Rust. I'm interested if https://github.com/rochacbruno/rust-python-example would help, which can replace fuzzy_match() :
|
def fuzzy_match(query, candidates): |
The result shows that using Rust could be 10x faster, see #146, #147.
-
job
- [-]
Use a timer for reading the output of vim job periodly, then the callback won't be called that many times. This branch is my try with timer. Using a timer helps a lot, but some messages are dropped unexpected, not sure if that's bug of Vim or my code. I did not investigate further as I have achived the same goal with maple as follows.
- Don't have to output all the fuzzy filtered items, we only show the top N candidates and care about the number of total candidates. The payload of async job will be significantly decreased if only these essential information is returned.(#181)
|