[前][次][番号順一覧][スレッド一覧]

ruby-changes:63620

From: Alan <ko1@a...>
Date: Tue, 17 Nov 2020 07:41:54 +0900 (JST)
Subject: [ruby-changes:63620] 68ffc8db08 (master): Set allocator on class creation

https://git.ruby-lang.org/ruby.git/commit/?id=68ffc8db08

From 68ffc8db088a7b29613a3746be5cc996be9f66fe Mon Sep 17 00:00:00 2001
From: Alan Wu <XrXr@u...>
Date: Thu, 12 Nov 2020 15:15:30 -0500
Subject: Set allocator on class creation

Allocating an instance of a class uses the allocator for the class. When
the class has no allocator set, Ruby looks for it in the super class
(see rb_get_alloc_func()).

It's uncommon for classes created from Ruby code to ever have an
allocator set, so it's common during the allocation process to search
all the way to BasicObject from the class with which the allocation is
being performed. This makes creating instances of classes that have
long ancestry chains more expensive than creating instances of classes
have that shorter ancestry chains.

Setting the allocator at class creation time removes the need to perform
a search for the alloctor during allocation.

This is a breaking change for C-extensions that assume that classes
created from Ruby code have no allocator set. Libraries that setup a
class hierarchy in Ruby code and then set the allocator on some parent
class, for example, can experience breakage. This seems like an unusual
use case and hopefully it is rare or non-existent in practice.

Rails has many classes that have upwards of 60 elements in the ancestry
chain and benchmark shows a significant improvement for allocating with
a class that includes 64 modules.

```
pre: ruby 3.0.0dev (2020-11-12T14:39:27Z master 6325866421)
post: ruby 3.0.0dev (2020-11-12T20:15:30Z cut-allocator-lookup)

Comparison:
                  allocate_8_deep
                post:  10336985.6 i/s
                 pre:   8691873.1 i/s - 1.19x  slower

                 allocate_32_deep
                post:  10423181.2 i/s
                 pre:   6264879.1 i/s - 1.66x  slower

                 allocate_64_deep
                post:  10541851.2 i/s
                 pre:   4936321.5 i/s - 2.14x  slower

                allocate_128_deep
                post:  10451505.0 i/s
                 pre:   3031313.5 i/s - 3.45x  slower
```

diff --git a/benchmark/object_allocate.yml b/benchmark/object_allocate.yml
new file mode 100644
index 0000000..93ff463
--- /dev/null
+++ b/benchmark/object_allocate.yml
@@ -0,0 +1,21 @@ https://github.com/ruby/ruby/blob/trunk/benchmark/object_allocate.yml#L1
+prelude: |
+  class Eight
+    8.times { include(Module.new) }
+  end
+  class ThirtyTwo
+    32.times { include(Module.new) }
+  end
+  class SixtyFour
+    64.times { include(Module.new) }
+  end
+  class OneTwentyEight
+    128.times { include(Module.new) }
+  end
+  # Disable GC to see raw throughput:
+  GC.disable
+benchmark:
+  allocate_8_deep: Eight.new
+  allocate_32_deep: ThirtyTwo.new
+  allocate_64_deep: SixtyFour.new
+  allocate_128_deep: OneTwentyEight.new
+loop_count: 100000
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 2fa9637..f902a65 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -4034,6 +4034,7 @@ vm_declare_class(ID id, rb_num_t flags, VALUE cbase, VALUE super) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L4034
     /* new class declaration */
     VALUE s = VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) ? super : rb_cObject;
     VALUE c = declare_under(id, cbase, rb_define_class_id(id, s));
+    rb_define_alloc_func(c, rb_get_alloc_func(c));
     rb_class_inherited(s, c);
     return c;
 }
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]