зеркало из https://github.com/github/ruby.git
Speed up hash literals by duping
This commit replaces the `newhashfromarray` instruction with a `duphash` instruction. Instead of allocating a new hash from an array stored in the Instruction Sequences, store a hash directly in the instruction sequences and dup it on execution. == Instruction sequence changes == ```ruby code = <<-eorby { "foo" => "bar", "baz" => "lol" } eorby insns = RubyVM::InstructionSequence.compile(code, __FILE__, nil, 0, frozen_string_literal: true) puts insns.disasm ``` On Ruby 2.5: ``` == disasm: #<ISeq:<compiled>@test.rb:0 (0,0)-(0,36)>==================== 0000 putobject "foo" 0002 putobject "bar" 0004 putobject "baz" 0006 putobject "lol" 0008 newhash 4 0010 leave ``` Ruby 2.6@r66174 3b6321083a2e3525da3b34d08a0b68bac094bd7f: ``` $ ./ruby test.rb == disasm: #<ISeq:<compiled>@test.rb:0 (0,0)-(0,36)> (catch: FALSE) 0000 newhashfromarray 2, ["foo", "bar", "baz", "lol"] 0003 leave ``` Ruby 2.6 + This commit: ``` $ ./ruby test.rb == disasm: #<ISeq:<compiled>@test.rb:0 (0,0)-(0,36)> (catch: FALSE) 0000 duphash {"foo"=>"bar", "baz"=>"lol"} 0002 leave ``` == Benchmark Results == Compared to 2.5.3: ``` $ make benchmark ITEM=hash_literal_small COMPARE_RUBY=/Users/aaron/.rbenv/versions/2.5.3/bin/ruby generating known_errors.inc known_errors.inc unchanged ./revision.h unchanged /Users/aaron/.rbenv/shims/ruby --disable=gems -rrubygems -I./benchmark/lib ./benchmark/benchmark-driver/exe/benchmark-driver \ --executables="compare-ruby::/Users/aaron/.rbenv/versions/2.5.3/bin/ruby -I.ext/common --disable-gem" \ --executables="built-ruby::./miniruby -I./lib -I. -I.ext/common -r./prelude --disable-gem" \ $(find ./benchmark -maxdepth 1 -name '*hash_literal_small*.yml' -o -name '*hash_literal_small*.rb' | sort) Calculating ------------------------------------- compare-ruby built-ruby hash_literal_small2 1.498 1.877 i/s - 1.000 times in 0.667581s 0.532656s hash_literal_small4 1.197 1.642 i/s - 1.000 times in 0.835375s 0.609160s hash_literal_small8 0.620 1.215 i/s - 1.000 times in 1.611638s 0.823090s Comparison: hash_literal_small2 built-ruby: 1.9 i/s compare-ruby: 1.5 i/s - 1.25x slower hash_literal_small4 built-ruby: 1.6 i/s compare-ruby: 1.2 i/s - 1.37x slower hash_literal_small8 built-ruby: 1.2 i/s compare-ruby: 0.6 i/s - 1.96x slower ``` Compared to r66255 ``` $ make benchmark ITEM=hash_literal_small COMPARE_RUBY=/Users/aaron/.rbenv/versions/ruby-trunk/bin/ruby generating known_errors.inc known_errors.inc unchanged ./revision.h unchanged /Users/aaron/.rbenv/shims/ruby --disable=gems -rrubygems -I./benchmark/lib ./benchmark/benchmark-driver/exe/benchmark-driver \ --executables="compare-ruby::/Users/aaron/.rbenv/versions/ruby-trunk/bin/ruby -I.ext/common --disable-gem" \ --executables="built-ruby::./miniruby -I./lib -I. -I.ext/common -r./prelude --disable-gem" \ $(find ./benchmark -maxdepth 1 -name '*hash_literal_small*.yml' -o -name '*hash_literal_small*.rb' | sort) Calculating ------------------------------------- compare-ruby built-ruby hash_literal_small2 1.567 1.831 i/s - 1.000 times in 0.638056s 0.546039s hash_literal_small4 1.298 1.652 i/s - 1.000 times in 0.770214s 0.605182s hash_literal_small8 0.873 1.216 i/s - 1.000 times in 1.145304s 0.822047s Comparison: hash_literal_small2 built-ruby: 1.8 i/s compare-ruby: 1.6 i/s - 1.17x slower hash_literal_small4 built-ruby: 1.7 i/s compare-ruby: 1.3 i/s - 1.27x slower hash_literal_small8 built-ruby: 1.2 i/s compare-ruby: 0.9 i/s - 1.39x slower ``` git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66258 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
00a3108096
Коммит
2f37847820
|
@ -3984,7 +3984,12 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_ro
|
|||
ADD_INSN1(ret, line, duparray, ary);
|
||||
}
|
||||
else { /* COMPILE_ARRAY_TYPE_HASH */
|
||||
ADD_INSN2(ret, line, newhashfromarray, INT2FIX(RARRAY_LEN(ary)/2), ary);
|
||||
VALUE hash;
|
||||
|
||||
hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
|
||||
rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash);
|
||||
iseq_add_mark_object_compile_time(iseq, hash);
|
||||
ADD_INSN1(ret, line, duphash, hash);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
23
insns.def
23
insns.def
|
@ -454,6 +454,16 @@ duparray
|
|||
val = rb_ary_resurrect(ary);
|
||||
}
|
||||
|
||||
/* dup hash */
|
||||
DEFINE_INSN
|
||||
duphash
|
||||
(VALUE hash)
|
||||
()
|
||||
(VALUE val)
|
||||
{
|
||||
val = rb_hash_dup(hash);
|
||||
}
|
||||
|
||||
/* if TOS is an array expand, expand it to num objects.
|
||||
if the number of the array is less than num, push nils to fill.
|
||||
if it is greater than num, exceeding elements are dropped.
|
||||
|
@ -514,19 +524,6 @@ newhash
|
|||
}
|
||||
}
|
||||
|
||||
/* make new Hash object from (frozen) Array object */
|
||||
DEFINE_INSN
|
||||
newhashfromarray
|
||||
(rb_num_t num, VALUE ary)
|
||||
()
|
||||
(VALUE hash)
|
||||
// attr bool leaf = false; /* rb_hash_bulk_insert() can call methods. */
|
||||
{
|
||||
VM_ASSERT(num * 2 == (rb_num_t)RARRAY_LEN(ary));
|
||||
hash = rb_hash_new_with_size(num);
|
||||
rb_hash_bulk_insert(num * 2, RARRAY_CONST_PTR_TRANSIENT(ary), hash);
|
||||
}
|
||||
|
||||
/* put new Range object.(Range.new(low, high, flag)) */
|
||||
DEFINE_INSN
|
||||
newrange
|
||||
|
|
|
@ -239,8 +239,8 @@ class TestJIT < Test::Unit::TestCase
|
|||
assert_compile_once('a = 1; { a: a }', result_inspect: '{:a=>1}', insns: %i[newhash])
|
||||
end
|
||||
|
||||
def test_compile_insn_newhashfromarray
|
||||
assert_compile_once('{ a: 1 }', result_inspect: '{:a=>1}', insns: %i[newhashfromarray])
|
||||
def test_compile_insn_duphash
|
||||
assert_compile_once('{ a: 1 }', result_inspect: '{:a=>1}', insns: %i[duphash])
|
||||
end
|
||||
|
||||
def test_compile_insn_newrange
|
||||
|
|
Загрузка…
Ссылка в новой задаче