Actions
Bug #10232
closedTrivial change of IMMEDIATE VALUE bits layout
Description
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
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.
Actions
Like0
Like0Like0Like0Like0