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

Avoid repeated access to Ractor.current #474

Merged
merged 2 commits into from
Jan 30, 2021

Conversation

casperisfine
Copy link

When profiling our app against Ruby 3.0 I started seeing 2.3% of the time spent in Ractor.current which surprised me:

$ stackprof ~/Downloads/stackprof-shopify-boot-production-wall\ \(2\).dump --method Ractor.current
Ractor.current (<internal:ractor>:273)
  samples:  1464 self (2.3%)  /   1464 total (2.3%)
  callers:
     943  (   64.4%)  Psych.config
     521  (   35.6%)  Psych::Visitors::Visitor#dispatch
  code:
        SOURCE UNAVAILABLE

It turns out it is called repeatedly to access Psych "globals".

in d4861854 @marcandre says benchmarking show Ractor locals are only 15% slower than constant access, but that surprises me.

Either way both properties are accessed from Visitor instances, and AFAICT these are not shareable, so I think we could simply cache these lookups, in the same way that Psych.domain_types is already cached.

Let me know if I missed something.

@casperisfine
Copy link
Author

A quick micro-benchmark, that should be somewhat representative:

require 'benchmark/ips'

class RactorCurrent
  def config
    Ractor.current[:config] ||= {}
  end
end

class CachedRactorCurrent
  def initialize
    @config = (Ractor.current[:config] ||= {})
  end

  def config
    @config 
  end
end

regular = RactorCurrent.new
cached = CachedRactorCurrent.new

Benchmark.ips do |x|
  x.report('regular') { regular.config }
  x.report('cached') { cached.config }
  x.compare!
end
Warming up --------------------------------------
             regular   142.424k i/100ms
              cached   250.030k i/100ms
Calculating -------------------------------------
             regular      1.422M (± 0.9%) i/s -      7.121M in   5.006590s
              cached      2.499M (± 1.5%) i/s -     12.502M in   5.004277s

Comparison:
              cached:  2498700.7 i/s
             regular:  1422475.7 i/s - 1.76x  (± 0.00) slower

@marcandre
Copy link
Member

This is clearly the way to go 👍.
Now I wish I had added the code I used to benchmark, looks like I might have messed something up, or I was calling Ractor#[] but not Ractor.current.
In any case, let's merge this and backport it to 3.0 too...

@marcandre
Copy link
Member

marcandre commented Jan 30, 2021

PS: Turns out I found my code in which I had tested different scenarios and I indeed get ~1.6x slower. I can't explain my mistake 🤷‍♂️.

@casperisfine
Copy link
Author

Eh, this kind of stuff happens to me all the time.

Thanks for the merge!

@casperisfine
Copy link
Author

s/merge/approval/ 🤦

@marcandre marcandre merged commit a2721a0 into ruby:master Jan 30, 2021
@marcandre
Copy link
Member

Failure doesn't appear to be related, merging.

@hsbt would it be possible to make a bugfix release for this (unless other changes are expected)?

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

Successfully merging this pull request may close these issues.

3 participants