From cef8325e186795858ba08ca22722f60c362878a4 Mon Sep 17 00:00:00 2001 From: normal Date: Tue, 30 Jun 2015 20:45:44 +0000 Subject: struct.c: speedup for big structs use simple custom open-addressing hash for big structs. Original-patch-by: Sokolov Yura aka funny_falcon in https://bugs.ruby-lang.org/issues/10585 * struct.c (AREF_HASH_THRESHOLD): new macro (id_back_members): new ID (struct_member_pos_ideal): new function (struct_member_pos_probe): ditto (struct_set_members): ditto (struct_member_pos): ditto (rb_struct_getmember): use struct_member_pos for O(1) access (rb_struct_aref_sym): ditto (rb_struct_aset_sym): ditto (setup_struct): call struct_set_members (struct_define_without_accessor): ditto (Init_Struct): initialize __members_back__ [ruby-core:66851] [ruby-core:69705] [ruby-core:69821] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51077 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- struct.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 124 insertions(+), 34 deletions(-) (limited to 'struct.c') diff --git a/struct.c b/struct.c index ff4501d03e..eda56733e2 100644 --- a/struct.c +++ b/struct.c @@ -11,12 +11,16 @@ #include "internal.h" #include "vm_core.h" +#include "id.h" + +/* only for struct[:field] access */ +#define AREF_HASH_THRESHOLD (10) VALUE rb_method_for_self_aref(VALUE name, VALUE arg, rb_insn_func_t func); VALUE rb_method_for_self_aset(VALUE name, VALUE arg, rb_insn_func_t func); VALUE rb_cStruct; -static ID id_members; +static ID id_members, id_back_members; static VALUE struct_alloc(VALUE); @@ -66,6 +70,110 @@ rb_struct_members(VALUE s) return members; } +static long +struct_member_pos_ideal(VALUE name, long mask) +{ + /* (id & (mask/2)) * 2 */ + return (SYM2ID(name) >> (ID_SCOPE_SHIFT - 1)) & mask; +} + +static long +struct_member_pos_probe(long prev, long mask) +{ + /* (((prev/2) * 5 + 1) & (mask/2)) * 2 */ + return (prev * 5 + 2) & mask; +} + +static VALUE +struct_set_members(VALUE klass, VALUE members) +{ + VALUE back; + + members = rb_ary_dup(members); + rb_obj_freeze(members); + + if (RARRAY_LEN(members) <= AREF_HASH_THRESHOLD) { + back = members; + } else { + long i, j, mask = 64; + VALUE name; + + while (mask < RARRAY_LEN(members) * 5) mask *= 2; + + back = rb_ary_new2(mask + 1); + rb_ary_store(back, mask, INT2FIX(RARRAY_LEN(members))); + mask -= 2; /* mask = (2**k-1)*2 */ + + for (i=0; i