diff options
author | k0kubun <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-02-13 15:58:38 +0000 |
---|---|---|
committer | k0kubun <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-02-13 15:58:38 +0000 |
commit | ddb65f0b037a3979aa31d39ba586537e9afa7f6e (patch) | |
tree | dc1aa3547022290cc7d36fd5d50c79ef4715db27 /tool/ruby_vm | |
parent | 6593c3af8d9490687180ae7f413561a41d5547d5 (diff) | |
download | ruby-ddb65f0b037a3979aa31d39ba586537e9afa7f6e.tar.gz |
mjit_compile.inc.erb: replace opt_key insn
with opt_send_without_block insn if call cache has valid ISeq.
If the receiver is not optimized target of opt_key (i.e. Hash or Array),
it triggers JIT cancel and it would be slow.
This change allows JIT to drop the check for Hash/Array and continue to
execute JIT even if the receiver is not Hash or Array.
See the following benchmark results. It's not improved so much, but it
would be effective when we achieve Ruby method inlining in
_mjit_compile_send.erb.
* Micro benchmark
Given the following bench.rb,
```
class HashWithIndifferentAccess < Hash
def []=(key, value)
super(key.to_s, value)
end
def [](key)
super(key.to_s)
end
end
indhash = HashWithIndifferentAccess.new
indhash[:foo] = 'bar'
key = 'foo'
100000000.times do
indhash[key]
end
```
** before
```
$ time ./ruby --disable-gems --jit-verbose=1 /tmp/bench.rb
JIT success (31.4ms): block in <main>@/tmp/bench.rb:15 -> /tmp/_ruby_mjit_p18206u0.c
JIT success (669.3ms): []@/tmp/bench.rb:6 -> /tmp/_ruby_mjit_p18206u1.c
Successful MJIT finish
./ruby --disable-gems --jit-verbose=1 /tmp/bench.rb 12.21s user 0.04s system 107% cpu 11.394 total
```
** after
```
$ time ./ruby --disable-gems --jit-verbose=1 /tmp/bench.rb
JIT success (41.0ms): block in <main>@/tmp/bench.rb:15 -> /tmp/_ruby_mjit_p17293u0.c
JIT success (679.0ms): []@/tmp/bench.rb:6 -> /tmp/_ruby_mjit_p17293u1.c
Successful MJIT finish
./ruby --disable-gems --jit-verbose=1 /tmp/bench.rb 11.54s user 0.06s system 108% cpu 10.726 total
```
The execution time is shortened.
* optcarrot benchmark
Optcarrot has no room to be improved by this change. Almost nothing is changed.
fps: 59.54 (before) -> 59.51 (after)
* discourse benchmark
I expected this to be improved a little, but it isn't too.
** before (JIT)
```
categories_admin:
50: 12
75: 13
90: 14
99: 22
home_admin:
50: 12
75: 13
90: 16
99: 22
topic_admin:
50: 12
75: 13
90: 15
99: 21
categories:
50: 18
75: 19
90: 23
99: 27
home:
50: 3
75: 4
90: 4
99: 12
topic:
50: 11
75: 11
90: 14
99: 20
```
** after (JIT)
```
categories_admin:
50: 12
75: 12
90: 16
99: 24
home_admin:
50: 12
75: 12
90: 14
99: 21
topic_admin:
50: 12
75: 13
90: 16
99: 21
categories:
50: 17
75: 18
90: 23
99: 32
home:
50: 3
75: 4
90: 4
99: 10
topic:
50: 11
75: 12
90: 13
99: 20
```
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62398 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'tool/ruby_vm')
-rw-r--r-- | tool/ruby_vm/views/mjit_compile.inc.erb | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/tool/ruby_vm/views/mjit_compile.inc.erb b/tool/ruby_vm/views/mjit_compile.inc.erb index 3c4dba6786..a23537e4bc 100644 --- a/tool/ruby_vm/views/mjit_compile.inc.erb +++ b/tool/ruby_vm/views/mjit_compile.inc.erb @@ -21,6 +21,11 @@ % 'opt_call_c_function', # low priority % ] % +% opt_send_without_block = RubyVM::Instructions.find { |i| i.name == 'opt_send_without_block' } +% if opt_send_without_block.nil? +% raise 'opt_send_without_block not found' +% end +% % # Available variables and macros in JIT-ed function: % # ec: the first argument of _mjitXXX % # reg_cfp: the second argument of _mjitXXX @@ -46,6 +51,8 @@ switch (insn) { case BIN(<%= insn.name %>): % if %w[opt_send_without_block send].include?(insn.name) <%= render 'mjit_compile_send', locals: { insn: insn } -%> +% elsif %w[opt_aref].include?(insn.name) # experimental. TODO: increase insns and make the list automatically by finding DISPATCH_ORIGINAL_INSN +<%= render 'mjit_compile_send', locals: { insn: opt_send_without_block } -%> % end <%= render 'mjit_compile_insn', locals: { insn: insn, dispatched: false } -%> break; |