badwtg1111 / vim

Automatically exported from code.google.com/p/vim
1 stars 0 forks source link

Ruby syntax highlighting w/ either cursorline or relativenumber causes lag from high CPU usage #282

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
With ruby syntax highlighting on, turning on cursorline or relativenumber 
settings causes lag due to high CPU usage when moving the cursor up and down. 
The conditions below exaggerbate the problem to help make it obvious and 
reproducible, but the same problem exists at lesser scale with smaller terminal 
sizes. This is a significant problem though, because when CPUs are otherwise 
bogged down (eg. when pair programming with someone via screen share on Google 
Hangouts), moving the cursor in a ruby file can be ridiculously slow.

What steps will reproduce the problem?
1. Temporarily rename ~/.vim/ and ~/.vimrc to ensure nothing but vanilla vim
2. Resize the terminal window so that ~100 lines are visible (normal for large 
monitors)
3. Open a ruby file with non-trivial syntax: 
https://raw.githubusercontent.com/rails/rails/f43f56e/activerecord/lib/active_re
cord/associations.rb
4. :syntax on
5. :set relativenumber
6. Hold down j or <down> for 1-2 seconds. (Ensure the system's keyboard repeat 
rate is not slow, ideally maxed)
7. Notice that CPU usage for the vim process is at 100%, accompanied by choppy 
redrawing and lag. Upon releasing the j/<down> key, buffered keypresses 
continue to move the cursor down.

What is the expected behavior?
1. With the same file open and under the same conditions, :set syntax=java
2. Notice there is no longer excessive CPU usage or any lag when moving the 
cursor up and down. The cursor stops moving immediately when the key is 
released.

---

I understand that ruby's syntax is complex and nontrivial to parse. If there's 
no clear way to reduce CPU usage for parsing ruby syntax for syntax 
highlighting, are there other ways you can think of to prevent the syntax 
highlighting from having to be recalculated when the screen is redrawn for 
relativenumber and cursorline? Can we profile and find where the problem lies?

---

I can reproduce this in Vim 7.4 on both Ubuntu and OSX:

VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Nov 12 2014 20:26:50)
MacOS X (unix) version
Included patches: 1-488
Compiled by Homebrew
Huge version without GUI.  Features included (+) or not (-):
+acl             +farsi           +mouse_netterm   +syntax
+arabic          +file_in_path    +mouse_sgr       +tag_binary
+autocmd         +find_in_path    -mouse_sysmouse  +tag_old_static
-balloon_eval    +float           +mouse_urxvt     -tag_any_white
-browse          +folding         +mouse_xterm     -tcl
++builtin_terms  -footer          +multi_byte      +terminfo
+byte_offset     +fork()          +multi_lang      +termresponse
+cindent         -gettext         -mzscheme        +textobjects
-clientserver    -hangul_input    +netbeans_intg   +title
+clipboard       +iconv           +path_extra      -toolbar
+cmdline_compl   +insert_expand   +perl            +user_commands
+cmdline_hist    +jumplist        +persistent_undo +vertsplit
+cmdline_info    +keymap          +postscript      +virtualedit
+comments        +langmap         +printer         +visual
+conceal         +libcall         +profile         +visualextra
+cryptv          +linebreak       +python          +viminfo
+cscope          +lispindent      -python3         +vreplace
+cursorbind      +listcmds        +quickfix        +wildignore
+cursorshape     +localmap        +reltime         +wildmenu
+dialog_con      -lua             +rightleft       +windows
+diff            +menu            +ruby            +writebackup
+digraphs        +mksession       +scrollbind      -X11
-dnd             +modify_fname    +signs           -xfontset
-ebcdic          +mouse           +smartindent     -xim
+emacs_tags      -mouseshape      -sniff           -xsmp
+eval            +mouse_dec       +startuptime     -xterm_clipboard
+ex_extra        -mouse_gpm       +statusline      -xterm_save
+extra_search    -mouse_jsbterm   -sun_workshop    -xpm
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
  fall-back for $VIM: "/usr/local/share/vim"
Compilation: /usr/bin/clang -c -I. -Iproto -DHAVE_CONFIG_H   
-F/usr/local/Frameworks -DMACOS_X_UNIX  -Os -w -pipe -march=native 
-mmacosx-version-min=10.10 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Linking: /usr/bin/clang   -L. -L/usr/local/lib -L/usr/local/lib 
-F/usr/local/Frameworks -Wl,-headerpad_max_install_names -o vim        -lm  
-lncurses -liconv -framework Cocoa   -fstack-protector  
-L/System/Library/Perl/5.18/darwin-thread-multi-2level/CORE -lperl -framework 
Python   -lruby.2.0.0 -lobjc

AND

VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Aug 15 2013 11:04:13)
Included patches: 1-5
Modified by pkg-vim-maintainers@lists.alioth.debian.org
Compiled by buildd@
Huge version without GUI.  Features included (+) or not (-):
+arabic          +file_in_path    +mouse_sgr       +tag_binary
+autocmd         +find_in_path    -mouse_sysmouse  +tag_old_static
-balloon_eval    +float           +mouse_urxvt     -tag_any_white
-browse          +folding         +mouse_xterm     +tcl
++builtin_terms  -footer          +multi_byte      +terminfo
+byte_offset     +fork()          +multi_lang      +termresponse
+cindent         +gettext         -mzscheme        +textobjects
-clientserver    -hangul_input    +netbeans_intg   +title
-clipboard       +iconv           +path_extra      -toolbar
+cmdline_compl   +insert_expand   +perl            +user_commands
+cmdline_hist    +jumplist        +persistent_undo +vertsplit
+cmdline_info    +keymap          +postscript      +virtualedit
+comments        +langmap         +printer         +visual
+conceal         +libcall         +profile         +visualextra
+cryptv          +linebreak       +python          +viminfo
+cscope          +lispindent      -python3         +vreplace
+cursorbind      +listcmds        +quickfix        +wildignore
+cursorshape     +localmap        +reltime         +wildmenu
+dialog_con      +lua             +rightleft       +windows
+diff            +menu            +ruby            +writebackup
+digraphs        +mksession       +scrollbind      -X11
-dnd             +modify_fname    +signs           -xfontset
-ebcdic          +mouse           +smartindent     -xim
+emacs_tags      -mouseshape      -sniff           -xsmp
+eval            +mouse_dec       +startuptime     -xterm_clipboard
+ex_extra        +mouse_gpm       +statusline      -xterm_save
+extra_search    -mouse_jsbterm   -sun_workshop
+farsi           +mouse_netterm   +syntax
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
  fall-back for $VIM: "/usr/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H     -g -O2 -fstack-protector 
--param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security 
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1     -I/usr/include/tcl8.5  -D_REENTRANT=1 
 -D_THREAD_SAFE=1  -D_LARGEFILE64_SOURCE=1
Linking: gcc   -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -rdynamic 
-Wl,-export-dynamic -Wl,-E  -Wl,-Bsymbolic-functions -Wl,-z,relro 
-Wl,--as-needed -o vim        -lm -ltinfo -lnsl  -lselinux  -lacl -lattr -lgpm 
-ldl  -L/usr/lib -llua5.1 -Wl,-E  -fstack-protector -L/usr/local/lib  
-L/usr/lib/perl/5.14/CORE -lperl -ldl -lm -lpthread -lcrypt 
-L/usr/lib/python2.7/config-x86_64-linux-gnu

Original issue reported on code.google.com by nil...@gmail.com on 13 Nov 2014 at 4:26

GoogleCodeExporter commented 9 years ago
:set lazyredraw serves as a workaround, though the underlying problem still 
remains.

Original comment by nil...@gmail.com on 13 Nov 2014 at 4:53

GoogleCodeExporter commented 9 years ago
Looks like the syntax highlighting rules are expensive. Check the help at :h 
syntime

Here is a patch, that tries to deviate the most expensive patterns on my system 
(I have on around 60 lines visible (sorry no expensive monitor for me ;)) and 
tuned the most expensive patterns. Check, if it works for you. 

Original comment by chrisbr...@googlemail.com on 13 Nov 2014 at 7:10

Attachments:

GoogleCodeExporter commented 9 years ago
I applied your patch. It doesn't seem that any of the patterns you modified 
appear in my top 10 slowest. The rubyConstant pattern doesn't seem to match the 
one in the ruby.vim syntax file, so I'm a little confused.

Before:

  TOTAL      COUNT  MATCH   SLOWEST     AVERAGE   NAME               PATTERN
  0.017596   184    0       0.000693    0.000096  rubySymbol         []})\"':]\@<!\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],]\@=
  0.006892   184    0       0.000156    0.000037  rubySymbol         \%([{(,]\_s*\)\@<=\l\w*[!?]\=::\@!
  0.001577   188    4       0.000065    0.000008  rubyCapitalizedMethod \%(\%(^\|[^.]\)\.\s*\)\@<!\<\u\%(\w\|[^\x00-\x7F]\)*\>\%(\s*(\)*\s*(\@=
  0.001533   26     0       0.000109    0.000059  rubyFunction       \%([[:space:].]\|^\)\@<=\%(\[\]=\=\|\*\*\|[+-]@\=\|[*/%|&^~]\|<<\|>>\|[<>]=\=\|<=>\|===\|[=!]=\|[=!]\~\|!\|`\)\%([[:space:];#(]\|$\)\@=
  0.001517   248    86      0.000038    0.000006  rubyConstant       \%(\%(^\|[^.]\)\.\s*\)\@<!\<\u\%(\w\|[^\x00-\x7F]\)*\>\%(\s*(\)\@!
  0.001224   220    36      0.000028    0.000006  rubyKeywordAsMethod \%(\%(\.\@<!\.\)\|::\)\_s*\%(elsif\|end\|ensure\|false\|for\|if\|in\|module\|next\|nil\)\>
  0.001180   190    6       0.000042    0.000006  rubyConditionalExpression \%(\%(^\|\.\.\.\=\|[{:,;([<>~\*/%&^|+=-]\|\%(\<[_[:lower:]][_[:alnum:]]*\)\@<![?!]\)\s*\)\@<=\%(if\|unless\)\>
  0.001140   184    0       0.000030    0.000006  rubyKeywordAsMethod \%(\%(\.\@<!\.\)\|::\)\_s*\%(public\|require\|require_relative\|raise\|throw\|trap\|using\)\>
  0.001123   184    0       0.000028    0.000006  rubyFloat          \%(\%(\w\|[]})\"']\s*\)\@<!-\)\=\<\%(0\|[1-9]\d*\%(_\d\+\)*\)\%(\.\d\+\%(_\d\+\)*\)\=\%([eE][-+]\=\d\+\%(_\d\+\)*\)\>
  0.001099   184    0       0.000029    0.000006  rubyKeywordAsMethod \%(\%(\.\@<!\.\)\|::\)\_s*\%(undef\|unless\|until\|when\|while\|yield\|BEGIN\|END\|__FILE__\|__LINE__\)\>

After:

  TOTAL      COUNT  MATCH   SLOWEST     AVERAGE   NAME               PATTERN
  0.026836   278    0       0.000804    0.000097  rubySymbol         []})\"':]\@<!\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],]\@=
  0.010392   278    0       0.000180    0.000037  rubySymbol         \%([{(,]\_s*\)\@<=\l\w*[!?]\=::\@!
  0.002325   380    137     0.000038    0.000006  rubyConstant       \%(\%(^\|[^.]\)\.\s*\)\@<!\<\u\%(\w\|[^\x00-\x7F]\)*\>\%(\s*(\)\@!
  0.002287   284    6       0.000078    0.000008  rubyCapitalizedMethod \%(\%(^\|[^.]\)\.\s*\)\@<!\<\u\%(\w\|[^\x00-\x7F]\)*\>\%(\s*(\)*\s*(\@=
  0.002259   39     0       0.000118    0.000058  rubyFunction       \%([[:space:].]\|^\)\@<=\%(\[\]=\=\|\*\*\|[+-]@\=\|[*/%|&^~]\|<<\|>>\|[<>]=\=\|<=>\|===\|[=!]=\|[=!]\~\|!\|`\)\%([[:space:];#(]\|$\)\@=
  0.001899   332    54      0.000047    0.000006  rubyKeywordAsMethod \%(\%(\.\@<!\.\)\|::\)\_s*\%(elsif\|end\|ensure\|false\|for\|if\|in\|module\|next\|nil\)\>
  0.001876   287    9       0.000078    0.000007  rubyConditionalExpression \%(\%(^\|\.\.\.\=\|[{:,;([<>~\*/%&^|+=-]\|\%(\<[_[:lower:]][_[:alnum:]]*\)\@<![?!]\)\s*\)\@<=\%(if\|unless\)\>
  0.001768   278    0       0.000031    0.000006  rubyKeywordAsMethod \%(\%(\.\@<!\.\)\|::\)\_s*\%(public\|require\|require_relative\|raise\|throw\|trap\|using\)\>
  0.001709   278    0       0.000037    0.000006  rubyKeywordAsMethod \%(\%(\.\@<!\.\)\|::\)\_s*\%(undef\|unless\|until\|when\|while\|yield\|BEGIN\|END\|__FILE__\|__LINE__\)\>
  0.001693   278    0       0.000038    0.000006  rubyKeywordAsMethod \%(\%(\.\@<!\.\)\|::\)\_s*\%(not\|or\|redo\|refine\|rescue\|retry\|return\|self\|super\|then\|true\)\>

Original comment by nil...@gmail.com on 13 Nov 2014 at 7:47

GoogleCodeExporter commented 9 years ago
I am looking at the before patterns.
Your syntime doesn't look that bad. I am surprised that your vim is so slow for 
you. You could try to add '\<' in front of the rubySymbol just after teh \@<! 
respectively the \@<= atoms and possibly at the end before the [!?]\= atom. 
Does it work better if you 'set re=1' in your .vimrc?
Since the report doesn't look that bad, perhaps you could try profiling with 
the latest Vim version?

Original comment by chrisbr...@googlemail.com on 13 Nov 2014 at 8:12

GoogleCodeExporter commented 9 years ago
I'm afraid I don't have much more time to spend on this. I'll work around it 
with lazyredraw for now.

Original comment by nil...@gmail.com on 13 Nov 2014 at 8:48

GoogleCodeExporter commented 9 years ago
Im just chiming in to add that I had the same or a similar issue and 'set re=1' 
made a huge difference for me with VIM 7.4 on Linux. 
In ruby files larger than a couple of hundred lines the processor would spike 
up to 100% and stay there for a few seconds every time I navigated up or down. 
After adding 'set re=1' to vimrc it still spikes up to 35% but it's no longer 
noticeable within the editor.

Original comment by shara...@gmail.com on 3 Dec 2014 at 9:42