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

Adopt the latest implementation for String#blank? from ActiveSupport and update benchmark result #33

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ken3ypa
Copy link

@ken3ypa ken3ypa commented Aug 12, 2023

Diffs

  • Adopted the latest implementation for String#blank? from ActiveSupport. (ref)
  • Update the benchmark to reflect the latest implementation.

I noticed a minor diffs between the latest code in ActiveSupport and benchmarking code in this gem.
After updating, the performance difference appears to be smaller; still this gem remains faster.

Thanks for making this gem. I really like this gem.

@ken3ypa ken3ypa force-pushed the use_new_ar_code_to_benches branch from 10a95f5 to f483e82 Compare August 12, 2023 01:40
@mjankowski
Copy link

I noticed same thing and was going to do similar PR.

I see about a ~1x to ~3x diff locally in benchmark. Still noticeable, but smaller than the ~10+ year old versions of ruby/rails this first worked on.

Also noticed the ruby versions listed in the README are pretty out of date ... might be worth a once over on the ruby/rails versions supported to assist anyone arriving here with an "is this still relevant, given perf improvements in ruby/rails?" sort of question.

@n-rodriguez
Copy link

Hi there! Is this still relevant, given perf improvements in ruby/rails? 😝 (I'm running Rails 7.2 and Ruby 3.3.4)

Thank you!

@mjankowski
Copy link

I added a copy of the latest Rails 8 blank? implementation to the benchmark, and I see this locally..

================== Test String Length: 0 ==================
ruby 3.3.6 (2024-11-05 revision 75015d4c1f) [arm64-darwin24]
Warming up --------------------------------------
          Fast Blank     6.423M i/100ms
  Fast ActiveSupport     6.557M i/100ms
          Slow Blank   457.277k i/100ms
      New Slow Blank     5.057M i/100ms
       Rails 8 Blank     4.056M i/100ms
Calculating -------------------------------------
          Fast Blank     64.628M (± 0.6%) i/s   (15.47 ns/i) -    327.590M in   5.069030s
  Fast ActiveSupport     65.698M (± 0.4%) i/s   (15.22 ns/i) -    334.389M in   5.089878s
          Slow Blank      4.658M (± 1.4%) i/s  (214.71 ns/i) -     23.321M in   5.008235s
      New Slow Blank     47.121M (±10.8%) i/s   (21.22 ns/i) -    237.660M in   5.103711s
       Rails 8 Blank     45.909M (± 9.6%) i/s   (21.78 ns/i) -    231.194M in   5.081250s

Comparison:
  Fast ActiveSupport: 65697724.1 i/s
          Fast Blank: 64627778.2 i/s - 1.02x  slower
      New Slow Blank: 47121045.6 i/s - 1.39x  slower
       Rails 8 Blank: 45909000.4 i/s - 1.43x  slower
          Slow Blank:  4657501.3 i/s - 14.11x  slower


================== Test String Length: 6 ==================
ruby 3.3.6 (2024-11-05 revision 75015d4c1f) [arm64-darwin24]
Warming up --------------------------------------
          Fast Blank     3.397M i/100ms
  Fast ActiveSupport     3.462M i/100ms
          Slow Blank   581.200k i/100ms
      New Slow Blank   901.615k i/100ms
       Rails 8 Blank     1.612M i/100ms
Calculating -------------------------------------
          Fast Blank     35.171M (± 1.1%) i/s   (28.43 ns/i) -    176.669M in   5.023770s
  Fast ActiveSupport     35.760M (± 0.6%) i/s   (27.96 ns/i) -    180.043M in   5.034976s
          Slow Blank      5.608M (± 1.5%) i/s  (178.31 ns/i) -     28.479M in   5.079308s
      New Slow Blank      8.936M (± 2.9%) i/s  (111.90 ns/i) -     45.081M in   5.048721s
       Rails 8 Blank     16.075M (± 2.2%) i/s   (62.21 ns/i) -     80.606M in   5.016802s

Comparison:
  Fast ActiveSupport: 35759522.4 i/s
          Fast Blank: 35170701.1 i/s - 1.02x  slower
       Rails 8 Blank: 16075265.9 i/s - 2.22x  slower
      New Slow Blank:  8936424.7 i/s - 4.00x  slower
          Slow Blank:  5608131.2 i/s - 6.38x  slower


================== Test String Length: 14 ==================
ruby 3.3.6 (2024-11-05 revision 75015d4c1f) [arm64-darwin24]
Warming up --------------------------------------
          Fast Blank     6.099M i/100ms
  Fast ActiveSupport     6.051M i/100ms
          Slow Blank   893.420k i/100ms
      New Slow Blank   555.400k i/100ms
       Rails 8 Blank     1.669M i/100ms
Calculating -------------------------------------
          Fast Blank     60.863M (± 1.0%) i/s   (16.43 ns/i) -    304.934M in   5.010616s
  Fast ActiveSupport     59.625M (± 1.0%) i/s   (16.77 ns/i) -    302.540M in   5.074608s
          Slow Blank      8.655M (± 2.5%) i/s  (115.54 ns/i) -     43.778M in   5.061295s
      New Slow Blank      5.386M (± 2.0%) i/s  (185.68 ns/i) -     27.215M in   5.055308s
       Rails 8 Blank     16.731M (± 3.1%) i/s   (59.77 ns/i) -     85.115M in   5.092575s

Comparison:
          Fast Blank: 60863229.8 i/s
  Fast ActiveSupport: 59624615.7 i/s - 1.02x  slower
       Rails 8 Blank: 16730799.6 i/s - 3.64x  slower
          Slow Blank:  8654809.4 i/s - 7.03x  slower
      New Slow Blank:  5385599.9 i/s - 11.30x  slower


================== Test String Length: 24 ==================
ruby 3.3.6 (2024-11-05 revision 75015d4c1f) [arm64-darwin24]
Warming up --------------------------------------
          Fast Blank     4.530M i/100ms
  Fast ActiveSupport     4.250M i/100ms
          Slow Blank   804.999k i/100ms
      New Slow Blank   510.141k i/100ms
       Rails 8 Blank     1.383M i/100ms
Calculating -------------------------------------
          Fast Blank     44.464M (± 1.0%) i/s   (22.49 ns/i) -    226.505M in   5.094640s
  Fast ActiveSupport     41.745M (± 1.1%) i/s   (23.95 ns/i) -    212.484M in   5.090676s
          Slow Blank      7.883M (± 3.1%) i/s  (126.85 ns/i) -     39.445M in   5.008313s
      New Slow Blank      5.100M (± 1.3%) i/s  (196.09 ns/i) -     25.507M in   5.002451s
       Rails 8 Blank     14.018M (± 0.6%) i/s   (71.34 ns/i) -     70.531M in   5.031843s

Comparison:
          Fast Blank: 44464464.5 i/s
  Fast ActiveSupport: 41745410.8 i/s - 1.07x  slower
       Rails 8 Blank: 14017581.0 i/s - 3.17x  slower
          Slow Blank:  7883372.4 i/s - 5.64x  slower
      New Slow Blank:  5099817.7 i/s - 8.72x  slower


================== Test String Length: 136 ==================
ruby 3.3.6 (2024-11-05 revision 75015d4c1f) [arm64-darwin24]
Warming up --------------------------------------
          Fast Blank     4.521M i/100ms
  Fast ActiveSupport     4.252M i/100ms
          Slow Blank   806.475k i/100ms
      New Slow Blank   533.680k i/100ms
       Rails 8 Blank     1.354M i/100ms
Calculating -------------------------------------
          Fast Blank     44.379M (± 1.3%) i/s   (22.53 ns/i) -    226.058M in   5.094697s
  Fast ActiveSupport     42.004M (± 1.0%) i/s   (23.81 ns/i) -    212.588M in   5.061687s
          Slow Blank      7.894M (± 2.5%) i/s  (126.68 ns/i) -     39.517M in   5.009225s
      New Slow Blank      5.377M (± 1.3%) i/s  (185.99 ns/i) -     27.218M in   5.063003s
       Rails 8 Blank     14.033M (± 0.7%) i/s   (71.26 ns/i) -     70.407M in   5.017337s

Comparison:
          Fast Blank: 44379021.9 i/s
  Fast ActiveSupport: 42003713.8 i/s - 1.06x  slower
       Rails 8 Blank: 14033428.6 i/s - 3.16x  slower
          Slow Blank:  7893899.6 i/s - 5.62x  slower
      New Slow Blank:  5376739.9 i/s - 8.25x  slower

Suggests there's still a ~1-3X benefit depending on string length.

@borama
Copy link

borama commented Jan 11, 2025

Here are some results on ruby 3.4.1 with YJIT and latest ActiveSupport implementation of blank?:

ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [x86_64-linux]

================== Test String Length: 0 ==================
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [x86_64-linux]
Warming up --------------------------------------
          Fast Blank     4.490M i/100ms
  Fast ActiveSupport     4.440M i/100ms
       Rails 8 blank     4.188M i/100ms
Calculating -------------------------------------
          Fast Blank    188.641M (± 1.2%) i/s    (5.30 ns/i) -    947.380M in   5.022870s
  Fast ActiveSupport    187.872M (± 1.1%) i/s    (5.32 ns/i) -    941.203M in   5.010384s
       Rails 8 blank    248.387M (± 0.9%) i/s    (4.03 ns/i) -      1.244B in   5.007652s

Comparison:
       Rails 8 blank: 248386874.8 i/s
          Fast Blank: 188640998.3 i/s - 1.32x  slower
  Fast ActiveSupport: 187872439.5 i/s - 1.32x  slower


================== Test String Length: 6 ==================
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [x86_64-linux]
Warming up --------------------------------------
          Fast Blank     2.745M i/100ms
  Fast ActiveSupport     2.449M i/100ms
       Rails 8 blank     1.475M i/100ms
Calculating -------------------------------------
          Fast Blank     26.365M (± 5.3%) i/s   (37.93 ns/i) -    131.757M in   5.012042s
  Fast ActiveSupport     24.440M (± 0.5%) i/s   (40.92 ns/i) -    122.429M in   5.009457s
       Rails 8 blank     14.814M (± 0.9%) i/s   (67.50 ns/i) -     75.202M in   5.076799s

Comparison:
          Fast Blank: 26365038.2 i/s
  Fast ActiveSupport: 24440119.3 i/s - 1.08x  slower
       Rails 8 blank: 14814029.7 i/s - 1.78x  slower


================== Test String Length: 14 ==================
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [x86_64-linux]
Warming up --------------------------------------
          Fast Blank     9.585M i/100ms
  Fast ActiveSupport     8.615M i/100ms
       Rails 8 blank     1.702M i/100ms
Calculating -------------------------------------
          Fast Blank     95.678M (± 1.2%) i/s   (10.45 ns/i) -    479.253M in   5.009759s
  Fast ActiveSupport     85.609M (± 0.8%) i/s   (11.68 ns/i) -    430.773M in   5.032218s
       Rails 8 blank     17.322M (± 0.7%) i/s   (57.73 ns/i) -     86.786M in   5.010387s

Comparison:
          Fast Blank: 95677623.9 i/s
  Fast ActiveSupport: 85608609.8 i/s - 1.12x  slower
       Rails 8 blank: 17322217.4 i/s - 5.52x  slower


================== Test String Length: 24 ==================
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [x86_64-linux]
Warming up --------------------------------------
          Fast Blank     3.787M i/100ms
  Fast ActiveSupport     3.465M i/100ms
       Rails 8 blank     1.257M i/100ms
Calculating -------------------------------------
          Fast Blank     37.701M (± 0.5%) i/s   (26.52 ns/i) -    189.334M in   5.022161s
  Fast ActiveSupport     33.638M (± 2.4%) i/s   (29.73 ns/i) -    169.784M in   5.050371s
       Rails 8 blank     12.706M (± 0.8%) i/s   (78.70 ns/i) -     64.122M in   5.046903s

Comparison:
          Fast Blank: 37700741.3 i/s
  Fast ActiveSupport: 33638103.1 i/s - 1.12x  slower
       Rails 8 blank: 12705926.9 i/s - 2.97x  slower


================== Test String Length: 136 ==================
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [x86_64-linux]
Warming up --------------------------------------
          Fast Blank     3.779M i/100ms
  Fast ActiveSupport     3.254M i/100ms
       Rails 8 blank     1.263M i/100ms
Calculating -------------------------------------
          Fast Blank     37.612M (± 0.7%) i/s   (26.59 ns/i) -    188.972M in   5.024578s
  Fast ActiveSupport     32.878M (± 6.5%) i/s   (30.42 ns/i) -    165.933M in   5.069937s
       Rails 8 blank     12.096M (± 5.5%) i/s   (82.67 ns/i) -     60.606M in   5.026549s

Comparison:
          Fast Blank: 37611555.9 i/s
  Fast ActiveSupport: 32877643.8 i/s - 1.14x  slower
       Rails 8 blank: 12095700.2 i/s - 3.11x  slower

Interestingly, YJIT makes the Rails (pure-ruby) version fastest for empty strings but ~5× slower compared to fast_blank for 14-byte strings. Otherwise, the results are very similar for me as those posted above.

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.

4 participants