ycm-core / YouCompleteMe

A code-completion engine for Vim
http://ycm-core.github.io/YouCompleteMe/
GNU General Public License v3.0
25.44k stars 2.81k forks source link

YCM killing my vim with GoLang #1461

Closed cfsalguero closed 9 years ago

cfsalguero commented 9 years ago

Since a couple of days, YCM started to use 99% CPU when using it with Go. I've disabled Syntastic but there is no change. There is any way to make it compile only when saving?

cfsalguero commented 9 years ago

just removed syntastic and all its configuration. There is a link to my config in a previous msg

vheon commented 9 years ago

@cfsalguero so with only syntastic but no YCM you have no problem, with YCM and no syntastic you have no problem, but with syntastic and YCM you have a slow experience??

cfsalguero commented 9 years ago

Really don't know what to say. I can give you the steps I did: 1) removed all plugins 2) removed go 3) reinstalled go 4) started from the very basic config 5) started to install 1 by 1 6) disabled syntastic because it started to work slow again Those were my steps. For me is very annoying too.

cfsalguero commented 9 years ago

Just as a comment, depending on the file I'm still have slowness so I decided to use just a plain vim

vheon commented 9 years ago

@cfsalguero if the project is Open Source could you share it?

cfsalguero commented 9 years ago

Sadly, no

cfsalguero commented 9 years ago

Hi again. First I want to thank you for taking care of this. I know you work for free and I really appreciate it and I'm really thankful. Second, I want to apologize for not being able to provide you with better information. I did this in my vim to try to have more information:

:profile start profile.log :profile func :profile file " At this point did slow actions " for example, I have a line that says something like this "Db.TruncateTables([]string{"table1", "table2", "table3", "table4"}) " and when I try to add a new table between quotes or I try to delete the quotes AND the text, the editor becomes unusable. :profile pause

and this is the result in the log file. I hope it helps. FUNCTION gitgutter#process_buffer() Called 1 time Total time: 0.000166 Self time: 0.000066

count total (s) self (s) 1 0.000032 0.000011 call gitgutter#utility#set_buffer(a:bufnr) 1 0.000081 0.000008 if gitgutter#utility#is_active() 1 0.000002 if g:gitgutter_sign_column_always call gitgutter#sign#add_dummy_sign() endif 1 0.000002 try 1 0.000013 0.000007 if !a:realtime || gitgutter#utility#has_fresh_changes() let diff = gitgutter#diff#run_diff(a:realtime || gitgutter#utility#has_unsaved_changes(), 1) call gitgutter#hunk#set_hunks(gitgutter#diff#parse_diff(diff)) let modified_lines = gitgutter#diff#process_hunks(gitgutter#hunk#hunks())

                                if len(modified_lines) > g:gitgutter_max_signs
                                  call gitgutter#utility#warn('exceeded maximum number of signs (configured by g:gitgutter_max_signs).')
                                  call gitgutter#sign#clear_signs()
                                  return
                                endif

                                if g:gitgutter_signs || g:gitgutter_highlight_lines
                                  call gitgutter#sign#update_signs(modified_lines)
                                endif

                                call gitgutter#utility#save_last_seen_change()
                              endif
1              0.000001     catch /diff failed/
                              call gitgutter#hunk#reset()
                            endtry
1              0.000001   else
                            call gitgutter#hunk#reset()
                          endif

FUNCTION 70_OnCursorMovedNormalMode() Called 57 times Total time: 0.048729 Self time: 0.007228

count total (s) self (s) 57 0.001823 0.000238 if !s:AllowedToCompleteInCurrentFile() return endif

57 0.040154 0.000238 call s:OnFileReadyToParse() 57 0.006591 py ycm_state.OnCursorMoved()

FUNCTION 70_UpdateDiagnosticNotifications() Called 59 times Total time: 0.000825 Self time: 0.000580

count total (s) self (s) 59 0.000640 0.000395 let should_display_diagnostics = g:ycm_show_diagnostics_ui && s:DiagnosticUiSupportedForCurrentFiletype() && pyeval( 'ycm_state.NativeFiletypeCompletionUsable()' )

59 0.000065 if !should_display_diagnostics 59 0.000040 return endif

                          py ycm_state.UpdateDiagnosticInterface()

FUNCTION gitgutter#utility#not_git_dir() Called 1 time Total time: 0.000041 Self time: 0.000024

count total (s) self (s) 1 0.000040 0.000023 return gitgutter#utility#full_path_to_directory_of_file() !~ '[/].git($|[/])'

FUNCTION 70_SetUpCompleteopt() Called 1 time Total time: 0.000018 Self time: 0.000018

count total (s) self (s) " Some plugins (I'm looking at you, vim-notes) change completeopt by for " instance adding 'longest'. This breaks YCM. So we force our settings. " There's no two ways about this: if you want to use YCM then you have to " have these completeopt settings, otherwise YCM won't work at all.

                          " We need menuone in completeopt, otherwise when there's only one candidate
                          " for completion, the menu doesn't show up.
1              0.000006   set completeopt-=menu
1              0.000002   set completeopt+=menuone

                          " This is unnecessary with our features. People use this option to insert
                          " the common prefix of all the matches and then add more differentiating chars
                          " so that they can select a more specific match. With our features, they
                          " don't need to insert the prefix; they just type the differentiating chars.
                          " Also, having this option set breaks the plugin.
1              0.000002   set completeopt-=longest

1              0.000002   if g:ycm_add_preview_to_completeopt
                            set completeopt+=preview
                          endif

FUNCTION 70_UpdateCursorMoved() Called 2 times Total time: 0.000039 Self time: 0.000039

count total (s) self (s) 2 0.000017 let current_position = getpos('.') 2 0.000005 let s:cursor_moved = current_position != s:old_cursor_position

2              0.000009   let s:moved_vertically_in_insert_mode = s:old_cursor_position != [] && current_position[ 1 ] != s:old_cursor_position[ 1 ]

2              0.000004   let s:old_cursor_position = current_position

FUNCTION gitgutter#utility#set_buffer() Called 1 time Total time: 0.000021 Self time: 0.000021

count total (s) self (s) 1 0.000004 let s:bufnr = a:bufnr 1 0.000016 let s:file = resolve(bufname(a:bufnr))

FUNCTION 70_OnCursorHold() Called 1 time Total time: 0.000123 Self time: 0.000024

count total (s) self (s) 1 0.000037 0.000008 if !s:AllowedToCompleteInCurrentFile() return endif

1   0.000026   0.000008   call s:SetUpCompleteopt()
1   0.000059   0.000007   call s:OnFileReadyToParse()

FUNCTION 70_OnInsertLeave() Called 1 time Total time: 0.002644 Self time: 0.002558

count total (s) self (s) 1 0.000050 0.000009 if !s:AllowedToCompleteInCurrentFile() return endif

1              0.000003   let s:omnifunc_mode = 0
1   0.000050   0.000005   call s:OnFileReadyToParse()
1              0.002529   py ycm_state.OnInsertLeave()
1              0.000005   if g:ycm_autoclose_preview_window_after_completion || g:ycm_autoclose_preview_window_after_insertion
                            call s:ClosePreviewWindowIfNeeded()
                          endif

FUNCTION 58_Highlight_Matching_Pair() Called 76 times Total time: 0.013880 Self time: 0.013880

count total (s) self (s) " Remove any previous match. 76 0.000591 if exists('w:paren_hl_on') && w:paren_hl_on 5 0.000018 3match none 5 0.000018 let w:paren_hl_on = 0 5 0.000008 endif

                          " Avoid that we remove the popup menu.
                          " Return when there are no colors (looks like the cursor jumps).

76 0.000398 if pumvisible() || (&t_Co < 8 && !has("gui_running")) return endif

                          " Get the character under the cursor and check if it's in 'matchpairs'.

76 0.000240 let c_lnum = line('.') 76 0.000212 let c_col = col('.') 76 0.000076 let before = 0

76 0.000401 let c = getline(c_lnum)[c_col - 1] 76 0.001166 let plist = split(&matchpairs, '.\zs[:,]') 76 0.000265 let i = index(plist, c) 76 0.000087 if i < 0 " not found, in Insert mode try character before the cursor 72 0.000247 if c_col > 1 && (mode() == 'i' || mode() == 'R') 2 0.000003 let before = 1 2 0.000006 let c = getline(c_lnum)[c_col - 2] 2 0.000006 let i = index(plist, c) 2 0.000001 endif 72 0.000065 if i < 0 " not found, nothing to do 71 0.000068 return endif 1 0.000001 endif

                          " Figure out the arguments for searchpairpos().
5              0.000006   if i % 2 == 0
3              0.000004     let s_flags = 'nW'
3              0.000010     let c2 = plist[i + 1]
3              0.000003   else
2              0.000004     let s_flags = 'nbW'
2              0.000004     let c2 = c
2              0.000004     let c = plist[i - 1]
2              0.000001   endif
5              0.000009   if c == '['
2              0.000002     let c = '\['
2              0.000003     let c2 = '\]'
2              0.000001   endif

                          " Find the match.  When it was just before the cursor move it there for a
                          " moment.
5              0.000005   if before > 0
1              0.000004     let save_cursor = winsaveview()
1              0.000004     call cursor(c_lnum, c_col - before)
1              0.000000   endif

                          " When not in a string or comment ignore matches inside them.
                          " We match "escape" for special items, such as lispEscapeSpecial.
5              0.000019   let s_skip ='synIDattr(synID(line("."), col("."), 0), "name") ' . '=~?  "string\\|character\\|singlequote\\|escape\\|comment"'
5              0.005092   execute 'if' s_skip '| let s_skip = 0 | endif'

                          " Limit the search to lines visible in the window.
5              0.000017   let stoplinebottom = line('w$')
5              0.000012   let stoplinetop = line('w0')
5              0.000005   if i % 2 == 0
3              0.000005     let stopline = stoplinebottom
3              0.000002   else
2              0.000003     let stopline = stoplinetop
2              0.000002   endif

                          " Limit the search time to 300 msec to avoid a hang on very long lines.
                          " This fails when a timeout is not supported.
5              0.000011   if mode() == 'i' || mode() == 'R'
1              0.000003     let timeout = exists("b:matchparen_insert_timeout") ? b:matchparen_insert_timeout : g:matchparen_insert_timeout
1              0.000001   else
4              0.000019     let timeout = exists("b:matchparen_timeout") ? b:matchparen_timeout : g:matchparen_timeout
4              0.000001   endif
5              0.000012   try
5              0.002572     let [m_lnum, m_col] = searchpairpos(c, '', c2, s_flags, s_skip, stopline, timeout)
5              0.000010   catch /E118/
                            " Can't use the timeout, restrict the stopline a bit more to avoid taking
                            " a long time on closed folds and long lines.
                            " The "viewable" variables give a range in which we can scroll while
                            " keeping the cursor at the same position.
                            " adjustedScrolloff accounts for very large numbers of scrolloff.
                            let adjustedScrolloff = min([&scrolloff, (line('w$') - line('w0')) / 2])
                            let bottom_viewable = min([line('$'), c_lnum + &lines - adjustedScrolloff - 2])
                            let top_viewable = max([1, c_lnum-&lines+adjustedScrolloff + 2])
                            " one of these stoplines will be adjusted below, but the current values are
                            " minimal boundaries within the current window
                            if i % 2 == 0
                              if has("byte_offset") && has("syntax_items") && &smc > 0
                            let stopbyte = min([line2byte("$"), line2byte(".") + col(".") + &smc * 2])
                            let stopline = min([bottom_viewable, byte2line(stopbyte)])
                              else
                            let stopline = min([bottom_viewable, c_lnum + 100])
                              endif
                              let stoplinebottom = stopline
                            else
                              if has("byte_offset") && has("syntax_items") && &smc > 0
                            let stopbyte = max([1, line2byte(".") + col(".") - &smc * 2])
                            let stopline = max([top_viewable, byte2line(stopbyte)])
                              else
                            let stopline = max([top_viewable, c_lnum - 100])
                              endif
                              let stoplinetop = stopline
                            endif
                            let [m_lnum, m_col] = searchpairpos(c, '', c2, s_flags, s_skip, stopline)
                          endtry

5              0.000007   if before > 0
1              0.000017     call winrestview(save_cursor)
1              0.000001   endif

                          " If a match is found setup match highlighting.
5              0.000014   if m_lnum > 0 && m_lnum >= stoplinetop && m_lnum <= stoplinebottom 
5              0.000122     exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) . 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
5              0.000009     let w:paren_hl_on = 1
5              0.000005   endif

FUNCTION gitgutter#utility#has_fresh_changes() Called 1 time Total time: 0.000006 Self time: 0.000006

count total (s) self (s) 1 0.000005 return getbufvar(s:bufnr, 'changedtick') != getbufvar(s:bufnr, 'gitgutter_last_tick')

FUNCTION 70_AllowedToCompleteInCurrentFile() Called 62 times Total time: 0.001760 Self time: 0.001760

count total (s) self (s) 62 0.000616 if empty( &filetype ) || getbufvar( winbufnr( winnr() ), "&buftype" ) ==# 'nofile' || &filetype ==# 'qf' return 0 endif

62 0.000140 if exists( 'b:ycm_largefile' ) return 0 endif

62 0.000339 let whitelist_allows = has_key( g:ycm_filetype_whitelist, '*' ) || has_key( g:ycm_filetype_whitelist, &filetype ) 62 0.000199 let blacklist_allows = !has_key( g:ycm_filetype_blacklist, &filetype )

62 0.000116 return whitelist_allows && blacklist_allows

FUNCTION 70_OnInsertEnter() Called 1 time Total time: 0.000054 Self time: 0.000014

count total (s) self (s) 1 0.000047 0.000007 if !s:AllowedToCompleteInCurrentFile() return endif

1              0.000003   let s:old_cursor_position = []

FUNCTION 70_SetUpYcmChangedTick() Called 59 times Total time: 0.000372 Self time: 0.000372

count total (s) self (s) 59 0.000349 let b:ycm_changedtick = get( b:, 'ycm_changedtick', { 'file_ready_to_parse' : -1, } )

FUNCTION gitgutter#utility#full_path_to_directory_of_file() Called 1 time Total time: 0.000017 Self time: 0.000017

count total (s) self (s) 1 0.000016 return fnamemodify(s:file, ':p:h')

FUNCTION 70_OnFileReadyToParse() Called 59 times Total time: 0.040013 Self time: 0.038816

count total (s) self (s) " We need to call this just in case there is no b:ycm_changetick; this can " happen for special buffers. 59 0.000589 0.000217 call s:SetUpYcmChangedTick()

                          " Order is important here; we need to extract any done diagnostics before
                          " reparsing the file again. If we sent the new parse request first, then
                          " the response would always be pending when we called
                          " UpdateDiagnosticNotifications.

59 0.001046 0.000221 call s:UpdateDiagnosticNotifications()

59 0.000171 let buffer_changed = b:changedtick != b:ycm_changedtick.file_ready_to_parse 59 0.000056 if buffer_changed 17 0.037587 py ycm_state.OnFileReadyToParse() 17 0.000033 endif 59 0.000169 let b:ycm_changedtick.file_ready_to_parse = b:changedtick

FUNCTION gitgutter#utility#exists_file() Called 1 time Total time: 0.000018 Self time: 0.000018

count total (s) self (s) 1 0.000018 return filereadable(s:file)

FUNCTION 70_BufferTextChangedSinceLastMoveInInsertMode() Called 2 times Total time: 0.000024 Self time: 0.000024

count total (s) self (s) 2 0.000002 if s:moved_vertically_in_insert_mode 1 0.000002 let s:previous_num_chars_on_current_line = -1 1 0.000001 return 0 endif

1              0.000003   let num_chars_in_current_cursor_line = strlen( getline('.') )

1              0.000002   if s:previous_num_chars_on_current_line == -1
                            let s:previous_num_chars_on_current_line = num_chars_in_current_cursor_line
                            return 0
                          endif

1              0.000003   let changed_text_on_current_line = num_chars_in_current_cursor_line != s:previous_num_chars_on_current_line
1              0.000002   let s:previous_num_chars_on_current_line = num_chars_in_current_cursor_line

1              0.000001   return changed_text_on_current_line

FUNCTION gitgutter#utility#is_active() Called 1 time Total time: 0.000073 Self time: 0.000014

count total (s) self (s) 1 0.000072 0.000013 return g:gitgutter_enabled && gitgutter#utility#exists_file() && gitgutter#utility#not_git_dir()

FUNCTION 70_DiagnosticUiSupportedForCurrentFiletype() Called 59 times Total time: 0.000245 Self time: 0.000245

count total (s) self (s) 59 0.000205 return get( s:diagnostic_ui_filetypes, &filetype, 0 )

FUNCTION 70_OnCursorMovedInsertMode() Called 2 times Total time: 0.000391 Self time: 0.000263

count total (s) self (s) 2 0.000074 0.000009 if !s:AllowedToCompleteInCurrentFile() return endif

2              0.000220   py ycm_state.OnCursorMoved()
2   0.000051   0.000012   call s:UpdateCursorMoved()

                          " Basically, we need to only trigger the completion menu when the user has
                          " inserted or deleted a character, NOT just when the user moves in insert mode
                          " (with, say, the arrow keys). If we trigger the menu even on pure moves, then
                          " it's impossible to move in insert mode since the up/down arrows start moving
                          " the selected completion in the completion menu. Yeah, people shouldn't be
                          " moving in insert mode at all (that's what normal mode is for) but explain
                          " that to the users who complain...
2   0.000034   0.000010   if !s:BufferTextChangedSinceLastMoveInInsertMode()
2              0.000001     return
                          endif

                          call s:IdentifierFinishedOperations()
                          if g:ycm_autoclose_preview_window_after_completion
                            call s:ClosePreviewWindowIfNeeded()
                          endif

                          if g:ycm_auto_trigger || s:omnifunc_mode
                            call s:InvokeCompletion()
                          endif

                          " We have to make sure we correctly leave omnifunc mode even when the user
                          " inserts something like a "operator[]" candidate string which fails
                          " CurrentIdentifierFinished check.
                          if s:omnifunc_mode && !pyeval( 'base.LastEnteredCharIsIdentifierChar()')
                            let s:omnifunc_mode = 0
                          endif

FUNCTIONS SORTED ON TOTAL TIME count total (s) self (s) function 57 0.048729 0.007228 70_OnCursorMovedNormalMode() 59 0.040013 0.038816 70_OnFileReadyToParse() 76 0.013880 58_Highlight_Matching_Pair() 1 0.002644 0.002558 70_OnInsertLeave() 62 0.001760 70_AllowedToCompleteInCurrentFile() 59 0.000825 0.000580 70_UpdateDiagnosticNotifications() 2 0.000391 0.000263 70_OnCursorMovedInsertMode() 59 0.000372 70_SetUpYcmChangedTick() 59 0.000245 70_DiagnosticUiSupportedForCurrentFiletype() 1 0.000166 0.000066 gitgutter#process_buffer() 1 0.000123 0.000024 70_OnCursorHold() 1 0.000073 0.000014 gitgutter#utility#is_active() 1 0.000054 0.000014 70_OnInsertEnter() 1 0.000041 0.000024 gitgutter#utility#not_git_dir() 2 0.000039 70_UpdateCursorMoved() 2 0.000024 70_BufferTextChangedSinceLastMoveInInsertMode() 1 0.000021 gitgutter#utility#set_buffer() 1 0.000018 70_SetUpCompleteopt() 1 0.000018 gitgutter#utility#exists_file() 1 0.000017 gitgutter#utility#full_path_to_directory_of_file()

FUNCTIONS SORTED ON SELF TIME count total (s) self (s) function 59 0.040013 0.038816 70_OnFileReadyToParse() 76 0.013880 58_Highlight_Matching_Pair() 57 0.048729 0.007228 70_OnCursorMovedNormalMode() 1 0.002644 0.002558 70_OnInsertLeave() 62 0.001760 70_AllowedToCompleteInCurrentFile() 59 0.000825 0.000580 70_UpdateDiagnosticNotifications() 59 0.000372 70_SetUpYcmChangedTick() 2 0.000391 0.000263 70_OnCursorMovedInsertMode() 59 0.000245 70_DiagnosticUiSupportedForCurrentFiletype() 1 0.000166 0.000066 gitgutter#process_buffer() 2 0.000039 70_UpdateCursorMoved() 1 0.000123 0.000024 70_OnCursorHold() 1 0.000041 0.000024 gitgutter#utility#not_git_dir() 2 0.000024 70_BufferTextChangedSinceLastMoveInInsertMode() 1 0.000021 gitgutter#utility#set_buffer() 1 0.000018 70_SetUpCompleteopt() 1 0.000018 gitgutter#utility#exists_file() 1 0.000017 gitgutter#utility#full_path_to_directory_of_file() 1 0.000073 0.000014 gitgutter#utility#is_active() 1 0.000054 0.000014 70_OnInsertEnter()

oblitum commented 9 years ago

@ekfriis so, I've tried it on OS X and even though it's overriding vim-go, I'm not seeing any issues. I think I'll stick with this setup, YCM overrides completion but I still take the rest from vim-go without issues I hope. Thanks!

oblitum commented 9 years ago

@ekfriis I've one concern though. Compared to other completion options even on YCM, the one built into YCM for golang is putting function prototype information at the type, instead of directly at the completion text. It looks like non conventional.

ekfriis commented 9 years ago

Hi @oblitum, glad to hear it is working for you. I'm not totally sure I understand your suggestion, can you give an example of what you think the completion should look like?

@cfsalguero sorry, just realized this fell off my stack. Looking at your profile, it seems the slowest functions are:

57 0.048729 0.007228 70_OnCursorMovedNormalMode() 59 0.040013 0.038816 70_OnFileReadyToParse() 76 0.013880 58_Highlight_Matching_Pair()

@Valloric, it looks like it is spending a lot of time in OnFileReadyToParse - is this normal? As far as I can tell, that is for the omnifunc(?), which should not be called at all in Go w/ the latest YCM.

vheon commented 9 years ago

@ekfriis OnFileReadyToParse the client send the buffer to the server, so ycmd is able to pick up new candidates for the identifier-based engine, and the server would also call the same function on the current semantic completer if it defines said function but the gocode completer does not.

oblitum commented 9 years ago

Hi @ekfriis, for example, you may check the C and C++ completion that's displayed by the GIF in the official README, BUT, I think it's not a big issue, since it's not a standard followed by all languages.