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
Use #start_with? and #[] for speed #21100
Conversation
While the readability may be slightly worse, the speed improvement is significant: Twice as fast when there's no leading "/" to remove, and over 4 times as fast when there is a leading "/". Benchmark: require 'benchmark/ips' def match(controller) if controller if m = controller.match(/\A\/(?<controller_without_leading_slash>.*)/) m[:controller_without_leading_slash] else controller end end end def start_with(controller) if controller if controller.start_with?('/'.freeze) controller[1..-1] else controller end end end Benchmark.ips do |x| x.report("match") { match("no_leading_slash") } x.report("start_with") { start_with("no_leading_slash") } x.compare! end Benchmark.ips do |x| x.report("match") { match("/a_leading_slash") } x.report("start_with") { start_with("/a_leading_slash") } x.compare! end Result (Ruby 2.2.2): Calculating ------------------------------------- match 70.324k i/100ms start_with 111.264k i/100ms ------------------------------------------------- match 1.468M (± 7.1%) i/s - 7.314M start_with 3.787M (± 3.5%) i/s - 18.915M Comparison: start_with: 3787389.4 i/s match: 1467636.4 i/s - 2.58x slower Calculating ------------------------------------- match 36.694k i/100ms start_with 86.071k i/100ms ------------------------------------------------- match 532.795k (± 4.7%) i/s - 2.679M start_with 2.518M (± 5.8%) i/s - 12.566M Comparison: start_with: 2518366.8 i/s match: 532794.5 i/s - 4.73x slower
I ran this local and my test app does hit this optimization. Doing some math we save 4.3108037795403217e-07 seconds per iteration and I hit this 1776 times per request. So this PR would buy me 1776 * 4.3108037795403217e-07 # => 0.0007655987512463612 seconds per request or 0.7655987512463611 miliseconds per request. So over the course of 1000 requests we would save |
Use #start_with? and #[] for speed
Totally. Two of these patches would be 1.5 ms per request and 1.5 seconds over 1000 requests. 20 of them would save us 15 seconds over 1000 requests. 👏 |
#17316 👍 |
For me the readability is much better, not worse :D Nice find! |
Did anyone benchmark this on non-c rubies? JRuby, Rbx, etc? (Just curious) |
@bf4 You have the Power! Also no, I didn't. I don't think anyone else did either, though I would be surprised since |
@bf4 You made me curious as well, so I tried running the same benchmark file on Rubinius (I don’t have JRuby installed). The results are quite interesting:
On Rubinius, the regex version is actually faster than Also I’m a bit confused how to read “some x slower” message. The “1.50x slower” above actually means “33% slower”, right? |
On my late 2013 mbp with SSD and 16mg ram under rvm jruby-1.7.11
(Running with Rbx-2.2.6
jruby-9.0.0.0.pre1
@schneems By the power of OSS... |
@bf4 cool, i wonder if there's some optimizations to be made in rbx's `starts_with? https://github.com/rubinius/rubinius/blob/32b4d39faff249740c0235f41f4d40526a5085d6/kernel/common/string.rb#L2321 compared to https://github.com/ruby/ruby/blob/c7dc6a34b50e4d9d76c1fe9d2888ccb2aa6aeef3/string.c#L8202-L8215
I never use the |
@schneems Let’s fix it: evanphx/benchmark-ips#49 |
This is a follow-up to #21057 as per https://github.com/rails/rails/pull/21057/files#r36032324
While the readability may be slightly worse, the speed improvement is significant: Twice as fast when there's no leading
/
to remove, and over 4 times as fast when there is a leading/
.Benchmark:
Result (Ruby 2.2.2):
cc @schneems