Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve perf on lsp#omni#default_get_vim_completion_item() #823

Closed
prabirshrestha opened this issue May 24, 2020 · 5 comments
Closed

improve perf on lsp#omni#default_get_vim_completion_item() #823

prabirshrestha opened this issue May 24, 2020 · 5 comments

Comments

@prabirshrestha
Copy link
Owner

default_get_vim_completion_item is very slow and is used by asyncomplete-lsp for every items. Currently this is also O(n) which has huge impact on perf. Currently lsp#omni#get_kind_text seems to be the bottleneck here.

    let l:w = lsp#utils#_trim(l:word)
    let l:a = l:abbr . (l:expandable ? '~' : '')
    let l:k = '' " lsp#omni#get_kind_text(a:item, l:server_name)

    let l:completion = {
                \ 'word': l:w,
                \ 'abbr': l:a,
                \ 'menu': '',
                \ 'info': '',
                \ 'icase': 1,
                \ 'dup': 1,
                \ 'empty': 1,
                \ 'kind': l:k,
                \ }

with empty kind:

FUNCTIONS SORTED ON TOTAL TIME
count  total (s)   self (s)  function
 2136   0.605399   0.026396  lsp#omni#get_vim_completion_item()
 2136   0.579003   0.481802  lsp#omni#default_get_vim_completion_item()
    2   0.006310             lsp#omni#_clear_managed_user_data_map()
    2   0.000047             lsp#omni#get_managed_user_data_from_completed_item()

 2136   0.026611   0.015598     let l:w = lsp#utils#_trim(l:word)
 2136              0.011199     let l:a = l:abbr . (l:expandable ? '~' : '')
 2136              0.005335     let l:k = ""
                            
 2136              0.028805     let l:completion = { 'word': l:w, 'abbr': l:a, 'menu': '', 'info': '', 'icase': 1, 'dup': 1, 'empty': 1, 'kind': l:k, }

with kind:

FUNCTIONS SORTED ON TOTAL TIME
count  total (s)   self (s)  function
 2136   1.255712   0.034085  lsp#omni#get_vim_completion_item()
 2136   1.221627   0.790641  lsp#omni#default_get_vim_completion_item()
 2136   0.225893   0.225887  lsp#omni#get_kind_text()
    2   0.006481             lsp#omni#_clear_managed_user_data_map()
    2   0.000057             lsp#omni#get_managed_user_data_from_completed_item()

 2136   0.084985   0.061978     let l:w = lsp#utils#_trim(l:word)
 2136              0.013946     let l:a = l:abbr . (l:expandable ? '~' : '')
 2136   0.285552   0.059659     let l:k = lsp#omni#get_kind_text(a:item, l:server_name)
                            
 2136              0.044679     let l:completion = { 'word': l:w, 'abbr': l:a, 'menu': '', 'info': '', 'icase': 1, 'dup': 1, 'empty': 1, 'kind': l:k, }

Another bottleneck seems to be here.

count  total (s)   self (s)  function
                                " Add user_data.
 2136              0.005695     if s:is_user_data_support
 2136   0.113772   0.027700         let l:completion['user_data'] = s:create_user_data(a:item, l:server_name, l:complete_position)
 2136              0.003087     endif
@prabirshrestha
Copy link
Owner Author

The root cause here seems to be that most language servers are returning to many results as part of the initial items which calls get_vim_completion_item.

In the below case typescript language server is sending all possible completion items to show even though we type c. This can even cause thousands of items to be returned which in turn calls get_vim_completion_item which slows down everything.

function hello() {
    c|
}

But now if you have an object and press . it seems to be very fast since now the completion items are scoped. This is cause it may only return around 10-20 items which is very small compared to 1k+ items.

function hello() {
    console.
}

This means we might need to first filter items received from server.

@prabirshrestha
Copy link
Owner Author

\ 'kind': lsp#omni#get_kind_text(a:item, l:server_name) really seems to be a bottleneck for completion items. For typescript source code in emitter.ts I got 2,000 results for the first completion request which causes pause. As soon as I comment it out it seems to be smooth.

One option would be to automatically make kind empty if the length of autocomplete results is greater than some number. And that number apparently seems to be around 120. As soon as I start increasing it I see hangs.

Another option would be to do prefix match and set incomplete to 1 but apparently this seems a broken in asyncomplete.

@prabirshrestha
Copy link
Owner Author

Tried multiple solutions but the only got few perf improvements so went with a flag to disable it. #824

Also could be smart in asyncomplete-lsp to restore and enable the flag if the items are too big.

@prabirshrestha
Copy link
Owner Author

can also look into optimizing. create_user_data_key

FUNCTION  <SNR>221_create_user_data()
    Defined: ~/.config/nvim/plugins/vim-lsp/autoload/lsp/omni.vim:383
Called 1734 times
Total time:   0.069774
 Self time:   0.061052

count  total (s)   self (s)
 1734   0.034734   0.026012     let l:user_data_key = s:create_user_data_key(s:managed_user_data_key_base)
 1734              0.022960     let s:managed_user_data_map[l:user_data_key] = {   'complete_position': a:complete_position,   'server_name': a:server_name,   'completion_item': a:completion_item }
 1734              0.006453     let s:managed_user_data_key_base += 1
 1734              0.003786     return l:user_data_key

@stale
Copy link

stale bot commented Dec 4, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Dec 4, 2020
@stale stale bot closed this as completed Dec 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant