Speedup test_shape.rb

Many tests start by exhausting all shapes, which is a slow process.
By exposing a method to directly move the bump allocator forward
we cut test runtime in half.

Before:
```
Finished tests in 1.544756s
```

After:
```
Finished tests in 0.759733s,
```
This commit is contained in:
Jean Boussier 2023-11-21 17:23:56 +01:00 committed by Jean Boussier
parent 0745c0c5ef
commit 2d7fb9c2fa
2 changed files with 32 additions and 114 deletions

10
shape.c
View File

@ -1057,6 +1057,15 @@ rb_shape_shapes_available(VALUE self)
return INT2NUM(MAX_SHAPE_ID - (GET_SHAPE_TREE()->next_shape_id - 1));
}
static VALUE
rb_shape_exhaust(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 0, 1);
int offset = argc == 1 ? NUM2INT(argv[0]) : 0;
GET_SHAPE_TREE()->next_shape_id = MAX_SHAPE_ID - offset;
return Qnil;
}
VALUE rb_obj_shape(rb_shape_t* shape);
static enum rb_id_table_iterator_result collect_keys_and_values(ID key, VALUE value, void *ref)
@ -1239,5 +1248,6 @@ Init_shape(void)
rb_define_singleton_method(rb_cShape, "of", rb_shape_debug_shape, 1);
rb_define_singleton_method(rb_cShape, "root_shape", rb_shape_root_shape, 0);
rb_define_singleton_method(rb_cShape, "shapes_available", rb_shape_shapes_available, 0);
rb_define_singleton_method(rb_cShape, "exhaust_shapes", rb_shape_exhaust, -1);
#endif
}

View File

@ -191,12 +191,7 @@ class TestShapes < Test::Unit::TestCase
attr_reader :very_unique
end
obj = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
obj.instance_variable_set(:"@a#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
(RubyVM::Shape::SHAPE_MAX_VARIATIONS * 2).times do
TooComplex.new.instance_variable_set(:"@unique_#{_1}", 1)
@ -216,13 +211,7 @@ class TestShapes < Test::Unit::TestCase
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
class Hi; end
obj = Hi.new
i = 0
while RubyVM::Shape.shapes_available > 2
obj.instance_variable_set(:"@a#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes(3)
obj = Hi.new
i = 0
@ -243,26 +232,16 @@ class TestShapes < Test::Unit::TestCase
@a = 1
end
end
# Try to run out of shapes
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
A.new
end
RubyVM::Shape.exhaust_shapes
A.new
end;
end
def test_run_out_of_shape_for_class_ivar
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
i = 0
while RubyVM::Shape.shapes_available > 0
c = Class.new
c.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
c = Class.new
c.instance_variable_set(:@a, 1)
@ -282,12 +261,7 @@ class TestShapes < Test::Unit::TestCase
begin;
[].instance_variable_set(:@a, 1)
i = 0
o = Object.new
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
ary = 10.times.map { [] }
@ -302,12 +276,7 @@ class TestShapes < Test::Unit::TestCase
def test_run_out_of_shape_for_module_ivar
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
module Foo
@a = 1
@ -321,12 +290,7 @@ class TestShapes < Test::Unit::TestCase
def test_run_out_of_shape_for_class_cvar
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
i = 0
while RubyVM::Shape.shapes_available > 0
c = Class.new
c.class_variable_set(:"@@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
c = Class.new
@ -348,13 +312,7 @@ class TestShapes < Test::Unit::TestCase
class TooComplex < Hash
end
# Try to run out of shapes
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
tc = TooComplex.new
tc.instance_variable_set(:@a, 1)
@ -387,15 +345,10 @@ class TestShapes < Test::Unit::TestCase
a = Hi.new
# Try to run out of shapes
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
assert_equal 1,a.transition
assert_equal 1,a.transition
assert_equal 1, a.transition
assert_equal 1, a.transition
end;
end
@ -409,12 +362,7 @@ class TestShapes < Test::Unit::TestCase
end
end
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
a = A.new
assert_equal true, a.instance_variable_defined?(:@a)
@ -424,12 +372,7 @@ class TestShapes < Test::Unit::TestCase
def test_run_out_of_shape_instance_variable_defined_on_module
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
module A
@a = @b = @c = @d = 1
@ -445,12 +388,7 @@ class TestShapes < Test::Unit::TestCase
o = Object.new
10.times { |i| o.instance_variable_set(:"@a#{i}", i) }
i = 0
a = Object.new
while RubyVM::Shape.shapes_available > 2
a.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
o.remove_instance_variable(:@a0)
(1...10).each do |i|
@ -471,12 +409,7 @@ class TestShapes < Test::Unit::TestCase
a = A.new
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
a.remove_instance_variable(:@b)
assert_nil a.b
@ -506,12 +439,7 @@ class TestShapes < Test::Unit::TestCase
a = A.new
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 1
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
a.dup
end;
@ -522,12 +450,7 @@ class TestShapes < Test::Unit::TestCase
o = []
o.instance_variable_set(:@a, 1)
i = 0
o = Object.new
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
ary = 1_000_000.times.map { [] }
begin;
@ -546,12 +469,7 @@ class TestShapes < Test::Unit::TestCase
begin;
class Hi; end
obj = Hi.new
i = 0
while RubyVM::Shape.shapes_available > 2
obj.instance_variable_set(:"@a#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes(2)
obj = Module.new
3.times do
@ -571,12 +489,7 @@ class TestShapes < Test::Unit::TestCase
begin;
class Hi; end
obj = Hi.new
i = 0
while RubyVM::Shape.shapes_available > 2
obj.instance_variable_set(:"@a#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes(2)
obj = Object.new
i = 0
@ -748,12 +661,7 @@ class TestShapes < Test::Unit::TestCase
end
assert_equal [0, 1, 2, 3, 4], ivars
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
RubyVM::Shape.exhaust_shapes
object.remove_instance_variable(:@ivar_2)