-
Notifications
You must be signed in to change notification settings - Fork 113
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 performance of show_source
for large class
#249
Improve performance of show_source
for large class
#249
Conversation
prev_tokens = [] | ||
|
||
# chunk with line number | ||
tokens.chunk { |tok| tok[0][0] }.each do |lnum, chunk| | ||
code = lines[0..lnum].join |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prev_tokens = [] | |
# chunk with line number | |
tokens.chunk { |tok| tok[0][0] }.each do |lnum, chunk| | |
code = lines[0..lnum].join | |
code = +"" | |
prev_tokens = [] | |
# chunk with line number | |
tokens.chunk { |tok| tok[0][0] }.each do |lnum, chunk| | |
code << lines[lnum] |
You changed the way code
is constructed, but this seems like a new bottleneck in your code. The original code seems optimal.
before
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin19]
Rehearsal --------------------------------------------------------
2.401019 0.011546 2.412565 ( 2.414266)
----------------------------------------------- total: 2.412565sec
user system total real
2.420137 0.005364 2.425501 ( 2.426264)
after
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin19]
Rehearsal --------------------------------------------------------
1.028879 0.009408 1.038287 ( 1.039615)
----------------------------------------------- total: 1.038287sec
user system total real
1.000221 0.007454 1.007675 ( 1.008295)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(The code I suggested might skip lines that don't have any token, but I assume such lines don't impact compilation error checks. Such lines seem to have an on_ignored_nl
token.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
#249 actually slowed down how `code` is concatenated. The original way of creating `code` is faster. [before] user system total real 2.420137 0.005364 2.425501 ( 2.426264) [after] user system total real 1.000221 0.007454 1.007675 ( 1.008295) Theoretically, this implementation might skip lines that don't appear in Ripper tokens, but this assumes such lines don't impact whether the code passes compilation or not. At least normal blank lines seem to have an `on_ignored_nl` token anyway though.
ruby/irb#249 actually slowed down how `code` is concatenated. The original way of creating `code` is faster. [before] user system total real 2.420137 0.005364 2.425501 ( 2.426264) [after] user system total real 1.000221 0.007454 1.007675 ( 1.008295) Theoretically, this implementation might skip lines that don't appear in Ripper tokens, but this assumes such lines don't impact whether the code passes compilation or not. At least normal blank lines seem to have an `on_ignored_nl` token anyway though. ruby/irb@27dd2867cd
This patch improves performance of
show_source
command for large class.Problem
show_source
is slow for large class.For example,
show_source 'IRB::Irb'
is slow. It takes 3.6s in my environment.Because
RubyLex.ripper_lex_without_warning
is heavy but it is called on each line.Profiling
Solution
Call
RubyLex.ripper_lex_without_warning
just once, instead of calling it on each line.This change also stops calling
RubyLex#check-state
, but it usesRubyLex#process_continue
andcheck_code_block
directly. Because the other checks incheck_state
methods, such asprocess_literal_type
, are slow. This change makes 5x difference the speed.Benchmark
code
result (before)
result (after)
In this case, it will be 26.3x faster 🚀