From: ko1@... Date: 2014-09-12T01:27:32+00:00 Subject: [ruby-core:64979] [ruby-trunk - Bug #10232] [Open] Trivial change of IMMEDIATE VALUE bits layout Issue #10232 has been reported by Koichi Sasada. ---------------------------------------- Bug #10232: Trivial change of IMMEDIATE VALUE bits layout https://bugs.ruby-lang.org/issues/10232 * Author: Koichi Sasada * Status: Open * Priority: Normal * Assignee: Koichi Sasada * Category: core * Target version: current: 2.2.0 * ruby -v: 2.2 * Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN ---------------------------------------- The following patch improves performance a bit. ``` !USE_FLONUM ------------------------- ...xxxx xxx1 Fixnum ...0000 1110 Symbol ...0000 0000 Qfalse ...0000 0010 Qtrue ...0000 0100 Qnil ...0000 0110 Qundef USE_FLONUM ------------------------- ...xxxx xxx1 Fixnum ...xxxx xx10 Flonum ...0000 1100 Symbol ...0000 0000 Qfalse 0x00 = 0 ...0000 1000 Qnil 0x08 = 8 ...0001 0100 Qtrue 0x14 = 20 ...0011 0100 Qundef 0x34 = 52 #=> !USE_FLONUM ------------------------- xxxx xxxx xxx1 Fixnum 0x01 xxxx 0011 0010 Symbol 0x32 = 50 0000 0000 0000 Qfalse 0x00 0000 0000 0010 Qnil 0x02 0000 0001 0010 Qtrue 0x12 = 18 0000 0010 0010 Qundef 0x22 = 32 USE_FLONUM ------------------------- xxxx xxxx xxx1 Fixnum 0x01 xxxx xxxx xx10 Flonum 0x02 xxxx 0011 0100 Symbol 0x34 = 52 0000 0000 0000 Qfalse 0x00 = 0 0000 0000 0100 Qnil 0x04 = 4 0000 0001 0100 Qtrue 0x14 = 20 0000 0010 0100 Qundef 0x24 = 36 ``` ```patch Index: include/ruby/ruby.h =================================================================== --- include/ruby/ruby.h (revision 47531) +++ include/ruby/ruby.h (working copy) @@ -395,6 +395,27 @@ USE_FLONUM ...0000 1000 Qnil 0x08 = 8 ...0001 0100 Qtrue 0x14 = 20 ...0011 0100 Qundef 0x34 = 52 + +#=> + +!USE_FLONUM +------------------------- +xxxx xxxx xxx1 Fixnum 0x01 +xxxx 0011 0010 Symbol 0x32 = 50 +0000 0000 0000 Qfalse 0x00 +0000 0000 0010 Qnil 0x02 +0000 0001 0010 Qtrue 0x12 = 18 +0000 0010 0010 Qundef 0x22 = 32 + +USE_FLONUM +------------------------- +xxxx xxxx xxx1 Fixnum 0x01 +xxxx xxxx xx10 Flonum 0x02 +xxxx 0011 0100 Symbol 0x34 = 52 +0000 0000 0000 Qfalse 0x00 = 0 +0000 0000 0100 Qnil 0x04 = 4 +0000 0001 0100 Qtrue 0x14 = 20 +0000 0010 0100 Qundef 0x24 = 36 */ /* special constants - i.e. non-zero and non-fixnum constants */ @@ -402,26 +423,26 @@ enum ruby_special_consts { #if USE_FLONUM RUBY_Qfalse = 0x00, RUBY_Qtrue = 0x14, - RUBY_Qnil = 0x08, - RUBY_Qundef = 0x34, + RUBY_Qnil = 0x04, + RUBY_Qundef = 0x24, RUBY_IMMEDIATE_MASK = 0x07, RUBY_FIXNUM_FLAG = 0x01, RUBY_FLONUM_MASK = 0x03, RUBY_FLONUM_FLAG = 0x02, - RUBY_SYMBOL_FLAG = 0x0c, + RUBY_SYMBOL_FLAG = 0x34, RUBY_SPECIAL_SHIFT = 8 #else - RUBY_Qfalse = 0, - RUBY_Qtrue = 2, - RUBY_Qnil = 4, - RUBY_Qundef = 6, + RUBY_Qfalse = 0x00, + RUBY_Qtrue = 0x12, + RUBY_Qnil = 0x02, + RUBY_Qundef = 0x22, RUBY_IMMEDIATE_MASK = 0x03, RUBY_FIXNUM_FLAG = 0x01, RUBY_FLONUM_MASK = 0x00, /* any values ANDed with FLONUM_MASK cannot be FLONUM_FLAG */ RUBY_FLONUM_FLAG = 0x02, - RUBY_SYMBOL_FLAG = 0x0e, + RUBY_SYMBOL_FLAG = 0x32, RUBY_SPECIAL_SHIFT = 8 #endif }; @@ -1106,7 +1127,7 @@ struct RStruct { #define FL_USER18 (((VALUE)1)<<(FL_USHIFT+18)) #define FL_USER19 (((VALUE)1)<<(FL_USHIFT+19)) -#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !RTEST(x)) +#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !(x)) #define FL_ABLE(x) (!SPECIAL_CONST_P(x) && BUILTIN_TYPE(x) != T_NODE) #define FL_TEST_RAW(x,f) (RBASIC(x)->flags&(f)) @@ -1583,11 +1604,9 @@ rb_class_of(VALUE obj) if (FLONUM_P(obj)) return rb_cFloat; if (obj == Qtrue) return rb_cTrueClass; if (STATIC_SYM_P(obj)) return rb_cSymbol; - } - else if (!RTEST(obj)) { if (obj == Qnil) return rb_cNilClass; - if (obj == Qfalse) return rb_cFalseClass; } + else if (obj == Qfalse) return rb_cFalseClass; return RBASIC(obj)->klass; } @@ -1600,11 +1619,9 @@ rb_type(VALUE obj) if (obj == Qtrue) return T_TRUE; if (STATIC_SYM_P(obj)) return T_SYMBOL; if (obj == Qundef) return T_UNDEF; - } - else if (!RTEST(obj)) { if (obj == Qnil) return T_NIL; - if (obj == Qfalse) return T_FALSE; } + else if (obj == Qfalse) return T_FALSE; return BUILTIN_TYPE(obj); } ``` The change is: (1) IMMEDIATE_P(Qnil) => TRUE (2) SPECIAL_CONST_P(x) becomes a bit simple -> (IMMEDIATE_P(x) || !(x)) (1) can be incompatibility issue so that I don't propose this fix strongly. Interpreter core doesn't depends on this spec, but C-exts can be affected. Benchmark result is: http://www.atdot.net/sp/raw/stirbn (gitruby is modified version) Strange thing is: vm1_const ``` vm1_const Const = 1 i = 0 while i<30_000_000 # while loop 1 i += 1 j = Const k = Const end trunk 1.057002067565918 trunk 1.07387113571167 trunk 1.3638195991516113 trunk 1.076874017715454 trunk 1.0717082023620605 gitruby 0.7370171546936035 gitruby 0.7366814613342285 gitruby 0.7377498149871826 gitruby 0.7381434440612793 gitruby 0.7375714778900146 ``` vm1_const only repeats `getinlinecache' instruction. I'm not sure why it has impact. Change this program to repeat accessing constant more: ``` Const = 1 i = 0 while i<30_000_000 # while loop 1 i += 1 j = Const k = Const k = Const k = Const k = Const k = Const k = Const k = Const k = Const k = Const k = Const k = Const k = Const end trunk 2.2485034465789795 trunk 2.2310359477996826 trunk 2.2247872352600098 trunk 2.2434682846069336 trunk 2.225156307220459 gitruby 2.2048048973083496 gitruby 2.2114696502685547 gitruby 2.2110848426818848 gitruby 2.208353042602539 gitruby 2.2142462730407715 ``` It can be accidentally. Other variations: ``` vm1_const Const = 1 i = 0 while i<30_000_000 # while loop 1 i += 1 k = Const end trunk 0.6202449798583984 trunk 0.8297767639160156 trunk 0.6203830242156982 trunk 0.6206128597259521 trunk 0.6202561855316162 gitruby 0.6209316253662109 gitruby 0.6197938919067383 gitruby 0.6191442012786865 gitruby 0.6194281578063965 gitruby 0.6211118698120117 ``` ``` vm1_const Const = 1 i = 0 while i<30_000_000 # while loop 1 i += 1 j = Const k = Const l = Const end trunk 1.195659875869751 trunk 1.1864018440246582 trunk 1.1857333183288574 trunk 1.17852783203125 trunk 1.177058458328247 gitruby 1.1888437271118164 gitruby 1.1901893615722656 gitruby 1.1873669624328613 gitruby 1.187666893005371 gitruby 1.182875156402588 ``` It seems that such strange behaviour only on two Const accessing. -- https://bugs.ruby-lang.org/