-
-
Notifications
You must be signed in to change notification settings - Fork 21
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
Faster Sexp#line options #30
Comments
The logic causes some slowdown, but a bigger chunk than I thought was happening because of that stupid So, I will certainly do the latter... I'm not sure about adding
|
|
This is so fucking strange... using |
I wonder if I mean, it's pretty fast as-is, this is really micro-optimizing, but I do find Brakeman spends a considerable amount of time setting line numbers if I use a sampling profiler. |
My how machines and ruby versions have changed...
|
Out of curiosity, I made def sneaky_line n = nil
if n then
set_line n
else
@line ||= nil
end
end and it's 10% faster. Do you remember what the bugs were? Might be worth revisiting. |
Do you mean
If so, the issue was code like sexp1.line(sexp2.line) if |
What do you think about going back to the old version but provide a defensive one via en env var or something?I'm benchmarking the shit out of conditional and equality combinations... I'm currently leaning towards defaulting the arg to false instead of nil or some arbitrary object. False will get, non-integer will raise, otherwise set. That way nils will still be caught and handled. How's that sound? |
That works for me! Edit: To be clear, I mean the |
OK. After a lot of benchmarking I've discovered a few things. The most costly bit out of all of this is the optional argument. The comparisons against that cost isn't zero, but is effectively noise compared to the cost of setting up the call frame and evaluating the optional argument when called with no args. That is to say, if we want to squeeze all the performance from this that we can, we should move towards an explicit setter and getter. Combining them looked nice, but comes with a cost. To be fair, the cost isn't that much. These are all roughly equal in cost: def line_orig n = UNASSIGNED
if n != UNASSIGNED then
raise ArgumentError, "setting %p.line %p" % [self, n] unless Integer === n
@line = n
self
else
@line ||= nil
end
end
def line_false1 n = false
raise ArgumentError, "setting %p.line %p" % [self, n] unless
n == false or Integer === n
if n then
@line = n
self
else
@line ||= nil
end
end
def line_false2 n = false
if n then
raise ArgumentError, "setting %p.line %p" % [self, n] unless Integer === n
@line = n
self
else
raise ArgumentError, "setting %p.line %p" % [self, n] unless n == false
@line ||= nil
end
end
and it is only when we really start to change the design that we start to get improvements: def line_false3 n = false
if n then
@line = n
self
else
@line ||= nil
end
end
def line_false4
@line ||= nil
end
So, at this point, I'm tempted to just leave it be and start planning a migration to an explicit setter with a deprecation warning in the old Your old benchmark run on 3.1 (with a minor modification to allow for comparing attr_reader vs my original line:
|
Right now,
Sexp#line
can be used to either fetch or set the line number. This has led to some bugs which were addressed by ce28448But
Sexp#line
is quite a bit slower (relatively) due to the added logic. The method gets called a lot, so it might make sense to have a faster path.Benchmark code
Benchmark results
I did a rough search-and-replace of calls to
Sexp#line
in SexpProcessor and RubyParser. The performance difference is maybe 3-5%. So maybe not worth it?The method names could certainly use work. I like
Sexp#with_line
to suggest that it is returningself
.Sexp#lineno
orSexp#line_no
could be used for fetching? Since lines are often copied from existingSexp
s, maybe a method likeSexp#copy_line
to pass in aSexp
?Just thoughts, not attached to any of this.
The text was updated successfully, but these errors were encountered: