From 65651b34b1b5c2ef556ed44d5ebbd98838cfe8e6 Mon Sep 17 00:00:00 2001 From: normal Date: Tue, 9 Dec 2014 15:43:49 +0000 Subject: struct: avoid all O(n) behavior on access This avoids O(n) on lookups with structs over 10 members. This also avoids O(n) behavior on all assignments on Struct members. Members 0..9 still use existing C methods to read in O(1) time Benchmark results: vm2_struct_big_aref_hi* 1.305 vm2_struct_big_aref_lo* 1.157 vm2_struct_big_aset* 3.306 vm2_struct_small_aref* 1.015 vm2_struct_small_aset* 3.273 Note: I chose use loading instructions from an array instead of writing directly to linked-lists in compile.c for ease-of-maintainability. We may move the method definitions to prelude.rb-like files in the future. I have also tested this patch with the following patch to disable the C ref_func methods and ensured the test suite and rubyspec works --- a/struct.c +++ b/struct.c @@ -209,7 +209,7 @@ setup_struct(VALUE nstr, VALUE members) ID id = SYM2ID(ptr_members[i]); VALUE off = LONG2NUM(i); - if (i < N_REF_FUNC) { + if (0 && i < N_REF_FUNC) { rb_define_method_id(nstr, id, ref_func[i], 0); } else { * iseq.c (rb_method_for_self_aref, rb_method_for_self_aset): new methods to generate bytecode for struct.c [Feature #10575] * struct.c (rb_struct_ref, rb_struct_set): remove (define_aref_method, define_aset_method): new functions (setup_struct): use new functions * test/ruby/test_struct.rb: add test for struct >10 members * benchmark/bm_vm2_struct_big_aref_hi.rb: new benchmark * benchmark/bm_vm2_struct_big_aref_lo.rb: ditto * benchmark/bm_vm2_struct_big_aset.rb: ditto * benchmark/bm_vm2_struct_small_aref.rb: ditto * benchmark/bm_vm2_struct_small_aset.rb: ditto git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48748 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- benchmark/bm_vm2_struct_big_aref_hi.rb | 7 +++++++ benchmark/bm_vm2_struct_big_aref_lo.rb | 7 +++++++ benchmark/bm_vm2_struct_big_aset.rb | 7 +++++++ benchmark/bm_vm2_struct_small_aref.rb | 7 +++++++ benchmark/bm_vm2_struct_small_aset.rb | 7 +++++++ 5 files changed, 35 insertions(+) create mode 100644 benchmark/bm_vm2_struct_big_aref_hi.rb create mode 100644 benchmark/bm_vm2_struct_big_aref_lo.rb create mode 100644 benchmark/bm_vm2_struct_big_aset.rb create mode 100644 benchmark/bm_vm2_struct_small_aref.rb create mode 100644 benchmark/bm_vm2_struct_small_aset.rb (limited to 'benchmark') diff --git a/benchmark/bm_vm2_struct_big_aref_hi.rb b/benchmark/bm_vm2_struct_big_aref_hi.rb new file mode 100644 index 0000000000..22cb26b0a5 --- /dev/null +++ b/benchmark/bm_vm2_struct_big_aref_hi.rb @@ -0,0 +1,7 @@ +s = Struct.new(*('a'..'z').map { |x| x.to_sym }) +x = s.new +i = 0 +while i<6_000_000 # benchmark loop 2 + i += 1 + x.z # x[25] +end diff --git a/benchmark/bm_vm2_struct_big_aref_lo.rb b/benchmark/bm_vm2_struct_big_aref_lo.rb new file mode 100644 index 0000000000..5e61a7087e --- /dev/null +++ b/benchmark/bm_vm2_struct_big_aref_lo.rb @@ -0,0 +1,7 @@ +s = Struct.new(*('a'..'z').map { |x| x.to_sym }) +x = s.new +i = 0 +while i<6_000_000 # benchmark loop 2 + i += 1 + x.k # x[10] +end diff --git a/benchmark/bm_vm2_struct_big_aset.rb b/benchmark/bm_vm2_struct_big_aset.rb new file mode 100644 index 0000000000..5a1c3d16f3 --- /dev/null +++ b/benchmark/bm_vm2_struct_big_aset.rb @@ -0,0 +1,7 @@ +s = Struct.new(*('a'..'z').map { |x| x.to_sym }) +x = s.new +i = 0 +while i<6_000_000 # benchmark loop 2 + i += 1 + x.k = i # x[10] = i +end diff --git a/benchmark/bm_vm2_struct_small_aref.rb b/benchmark/bm_vm2_struct_small_aref.rb new file mode 100644 index 0000000000..8eaa555b41 --- /dev/null +++ b/benchmark/bm_vm2_struct_small_aref.rb @@ -0,0 +1,7 @@ +s = Struct.new(:a, :b, :c) +x = s.new +i = 0 +while i<6_000_000 # benchmark loop 2 + i += 1 + x.a +end diff --git a/benchmark/bm_vm2_struct_small_aset.rb b/benchmark/bm_vm2_struct_small_aset.rb new file mode 100644 index 0000000000..ecd0f95669 --- /dev/null +++ b/benchmark/bm_vm2_struct_small_aset.rb @@ -0,0 +1,7 @@ +s = Struct.new(:a, :b, :c) +x = s.new +i = 0 +while i<6_000_000 # benchmark loop 2 + i += 1 + x.a = i +end -- cgit v1.2.3