1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/internal
eileencodes b91b3bc771 Add a cache for class variables
Redo of 34a2acdac7 and
931138b006 which were reverted.

GitHub PR #4340.

This change implements a cache for class variables. Previously there was
no cache for cvars. Cvar access is slow due to needing to travel all the
way up th ancestor tree before returning the cvar value. The deeper the
ancestor tree the slower cvar access will be.

The benefits of the cache are more visible with a higher number of
included modules due to the way Ruby looks up class variables. The
benchmark here includes 26 modules and shows with the cache, this branch
is 6.5x faster when accessing class variables.

```
compare-ruby: ruby 3.1.0dev (2021-03-15T06:22:34Z master 9e5105c) [x86_64-darwin19]
built-ruby: ruby 3.1.0dev (2021-03-15T12:12:44Z add-cache-for-clas.. c6be009) [x86_64-darwin19]

|         |compare-ruby|built-ruby|
|:--------|-----------:|---------:|
|vm_cvar  |      5.681M|   36.980M|
|         |           -|     6.51x|
```

Benchmark.ips calling `ActiveRecord::Base.logger` from within a Rails
application. ActiveRecord::Base.logger has 71 ancestors. The more
ancestors a tree has, the more clear the speed increase. IE if Base had
only one ancestor we'd see no improvement. This benchmark is run on a
vanilla Rails application.

Benchmark code:

```ruby
require "benchmark/ips"
require_relative "config/environment"

Benchmark.ips do |x|
  x.report "logger" do
    ActiveRecord::Base.logger
  end
end
```

Ruby 3.0 master / Rails 6.1:

```
Warming up --------------------------------------
              logger   155.251k i/100ms
Calculating -------------------------------------
```

Ruby 3.0 with cvar cache /  Rails 6.1:

```
Warming up --------------------------------------
              logger     1.546M i/100ms
Calculating -------------------------------------
              logger     14.857M (± 4.8%) i/s -     74.198M in   5.006202s
```

Lastly we ran a benchmark to demonstate the difference between master
and our cache when the number of modules increases. This benchmark
measures 1 ancestor, 30 ancestors, and 100 ancestors.

Ruby 3.0 master:

```
Warming up --------------------------------------
            1 module     1.231M i/100ms
          30 modules   432.020k i/100ms
         100 modules   145.399k i/100ms
Calculating -------------------------------------
            1 module     12.210M (± 2.1%) i/s -     61.553M in   5.043400s
          30 modules      4.354M (± 2.7%) i/s -     22.033M in   5.063839s
         100 modules      1.434M (± 2.9%) i/s -      7.270M in   5.072531s

Comparison:
            1 module: 12209958.3 i/s
          30 modules:  4354217.8 i/s - 2.80x  (± 0.00) slower
         100 modules:  1434447.3 i/s - 8.51x  (± 0.00) slower
```

Ruby 3.0 with cvar cache:

```
Warming up --------------------------------------
            1 module     1.641M i/100ms
          30 modules     1.655M i/100ms
         100 modules     1.620M i/100ms
Calculating -------------------------------------
            1 module     16.279M (± 3.8%) i/s -     82.038M in   5.046923s
          30 modules     15.891M (± 3.9%) i/s -     79.459M in   5.007958s
         100 modules     16.087M (± 3.6%) i/s -     81.005M in   5.041931s

Comparison:
            1 module: 16279458.0 i/s
         100 modules: 16087484.6 i/s - same-ish: difference falls within error
          30 modules: 15891406.2 i/s - same-ish: difference falls within error
```

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2021-06-18 10:02:44 -07:00
..
array.h Remove unneeded rb_ary_ptr_use_start defination in internal/array.h (#4427) 2021-06-01 00:37:45 -07:00
bignum.h Add RBIMPL_RVALUE_EMBED_LEN_MAX neeeded by internal/bignum.h 2021-05-04 14:56:55 +02:00
bits.h get rid of using __builtin_unreachable directly [Bug #17787] 2021-04-10 16:05:01 +09:00
class.h Add a cache for class variables 2021-06-18 10:02:44 -07:00
compar.h
compile.h Warn more duplicate literal hash keys 2021-06-03 15:11:18 +09:00
compilers.h Update compilers.h [ci skip] 2021-01-05 01:06:07 +09:00
complex.h cdhash_cmp: can also take complex 2021-05-12 10:30:46 +09:00
cont.h Expose scheduler as public interface & bug fixes. (#3945) 2021-02-09 19:39:56 +13:00
dir.h
enc.h
encoding.h rb_enc_interned_str: handle autoloaded encodings 2021-03-22 21:37:48 +09:00
enum.h
enumerator.h
error.h
eval.h
file.h
fixnum.h
gc.h Protoized old pre-ANSI K&R style declarations and definitions 2021-05-07 00:04:36 +09:00
hash.h
imemo.h Partially revert 2c7d3b3a72 2021-04-27 17:05:19 +09:00
inits.h
io.h
load.h
loadpath.h
math.h
missing.h
numeric.h Allow inlining Integer#-@ and #~ 2020-12-22 22:32:19 -08:00
object.h RBASIC_SET_CLASS_RAW: follow strict aliasing rule 2021-03-02 17:47:28 +09:00
parse.h ast.rb: RubyVM::AST.parse and .of accepts save_script_lines: true 2021-06-18 02:34:27 +09:00
proc.h
process.h
random.h
range.h
rational.h cdhash_cmp: can take rational literals 2021-05-12 10:30:46 +09:00
re.h Warn more duplicate literal hash keys 2021-06-03 15:11:18 +09:00
sanitizers.h
serial.h
signal.h
static_assert.h
string.h Remove unneeded rb_str_initialize defination in internal/string.h (#4465) 2021-06-01 00:37:24 -07:00
struct.h
symbol.h
thread.h
time.h
transcode.h
util.h
variable.h
vm.h Make it possible to get AST::Node from Thread::Backtrace::Location 2021-06-18 03:35:38 +09:00
warnings.h Fix some typos by spell checker 2021-04-26 10:07:41 +09:00