Skip to content
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

String#=~ faster than String#match #59

Merged

Conversation

schneems
Copy link
Contributor

@schneems schneems commented Aug 6, 2015

If you're only looking for presence of a match and don't need the matchdata, use String#=~

schneems/rails@1bf50ba#commitcomment-12572839

If you're only looking for presence of a match and don't need the matchdata, use String#=~ 

schneems/rails@1bf50ba#commitcomment-12572839
schneems referenced this pull request in schneems/rails Aug 6, 2015
In `apply_inflections` a string is down cased and some whitespace stripped in the front (which allocate strings). This would normally be fine, however `uncountables` is a fairly small array (10 elements out of the box) and this method gets called a TON. Instead we can keep an array of valid regexes for each uncountable so we don't have to allocate new strings.

This change buys us 325,106 bytes of memory and 3,251 fewer objects per request.
@Arcovion
Copy link
Collaborator

Arcovion commented Aug 6, 2015

Regexp#=== is a tiny bit faster on my machine, worth including:

require 'benchmark/ips'

def fastest
  /boo/ === 'foo'.freeze
end

def fast
  'foo'.freeze =~ /boo/
end

def slow
  'foo'.freeze.match(/boo/)
end

Benchmark.ips do |bm|
  bm.report("Regexp#===") { fastest }
  bm.report("String#=~") { fast }
  bm.report("String#match") { slow }
  bm.compare!
end
Calculating -------------------------------------
          Regexp#===   116.319k i/100ms
           String#=~   119.576k i/100ms
        String#match   102.506k i/100ms
-------------------------------------------------
          Regexp#===      3.048M (± 1.5%) i/s -     15.238M
           String#=~      2.988M (± 1.4%) i/s -     14.947M
        String#match      2.482M (± 1.2%) i/s -     12.506M

Comparison:
          Regexp#===:  3047884.6 i/s
           String#=~:  2988148.2 i/s - 1.02x slower
        String#match:  2481615.6 i/s - 1.23x slower

@schneems
Copy link
Contributor Author

schneems commented Aug 6, 2015

Yep

Calculating -------------------------------------
           String#=~    66.023k i/100ms
        String#match    60.124k i/100ms
          String#===    70.747k i/100ms
-------------------------------------------------
           String#=~      1.798M (±10.3%) i/s -      8.913M
        String#match      1.374M (± 9.7%) i/s -      6.854M
          String#===      1.847M (± 9.8%) i/s -      9.197M

Seems good. How should I report this? I would like to have all 3 examples in the code and reported.

@Arcovion
Copy link
Collaborator

Arcovion commented Aug 6, 2015

Edited my comment as String#=== was wrong, I meant Regexp#===
Added example of how it might look...

@JuanitoFatas
Copy link
Contributor

How about list all possibilities (code/string/===-vs-=~-vs-match.rb)?

require "benchmark/ips"

def fastest
  "foo".freeze === /boo/
end

def faster
  "foo".freeze =~ /boo/
end

def fast
  /boo/ === "foo".freeze
end

def slow
  "foo".freeze.match(/boo/)
end

Benchmark.ips do |x|
  x.report("String#===") { fastest }
  x.report("Regexp#===") { faster }
  x.report("String#=~") { fast }
  x.report("String#match") { slow }
  x.compare!
end
ruby -v code/string/match-vs-=\~.rb
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]
Calculating -------------------------------------
          String#===   143.440k i/100ms
          Regexp#===    94.853k i/100ms
           String#=~    91.999k i/100ms
        String#match    88.397k i/100ms
-------------------------------------------------
          String#===      5.637M (± 7.4%) i/s -     28.114M
          Regexp#===      2.599M (± 5.4%) i/s -     12.995M
           String#=~      2.318M (± 7.7%) i/s -     11.592M
        String#match      1.905M (± 8.4%) i/s -      9.458M

Comparison:
          String#===:  5637360.8 i/s
          Regexp#===:  2599326.4 i/s - 2.17x slower
           String#=~:  2318149.8 i/s - 2.43x slower
        String#match:  1905484.8 i/s - 2.96x slower

@Arcovion
Copy link
Collaborator

Arcovion commented Aug 7, 2015

String#=== doesn't work, it's not the correct result.

@JuanitoFatas
Copy link
Contributor

String#=== doesn't work, it's not the correct result.

Yup. The #59 (comment) is wrong.

Let's keep this simple since the regexp need to flip the string to be compared to the end. Which is counterintuitive

JuanitoFatas added a commit that referenced this pull request Aug 7, 2015
@JuanitoFatas JuanitoFatas merged commit df633ee into fastruby:master Aug 7, 2015
schneems added a commit to schneems/rails that referenced this pull request Aug 7, 2015
@schneems
Copy link
Contributor Author

schneems commented Aug 7, 2015

It's a pretty big speed boost, we would have to rename it to Regexp#=== and we could put a warning in about not switching the arguments cause you'll get the wrong results

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants