[ruby-list:50764] 1.next は 1.succ よりなぜ遅い?
From:
"5.5" <5.5@...>
Date:
2019-05-29 19:53:55 UTC
List:
ruby-list #50764
5.5 と申します。
Integer#succ と Integer#next は同じメソッド(エイリアス)だと
思っていたので,next のほうがかなり遅いということを知って驚き
ました。
require "benchmark_driver"
Benchmark.driver do |r|
r.report "1.succ"
r.report "1.next"
r.report "1 + 1"
end
結果:
1.succ: 189403887.3 i/s
1 + 1: 106135608.4 i/s - 1.78x slower
1.next: 47203766.8 i/s - 4.01x slower
$ ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
よく分からないなりに numeric.c の↓ココ
https://github.com/ruby/ruby/blob/b72623012d74abdb06210153ed48c9e2fa075bbd/numeric.c#L3294-L3323
https://github.com/ruby/ruby/blob/b72623012d74abdb06210153ed48c9e2fa075bbd/numeric.c#L5617-L5618
とか見て「やっぱり同じなんでは?」と思ったのですが,
puts RubyVM::InstructionSequence.new("1.next").disasm
# =>
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(1,6)> (catch: FALSE)
0000 putobject_INT2FIX_1_ (
1)[Li]
0001 opt_send_without_block <callinfo!mid:next, argc:0,
ARGS_SIMPLE>, <callcache>
0004 leave
puts RubyVM::InstructionSequence.new("1.succ").disasm
# =>
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(1,6)> (catch: FALSE)
0000 putobject_INT2FIX_1_ (
1)[Li]
0001 opt_succ <callinfo!mid:succ, argc:0,
ARGS_SIMPLE>, <callcache>
0004 leave
を見ると,opt_send_without_block と opt_succ の違いに
なっています。
opt_succ って何だろうと,思ったら,るびまの
「YARV Maniacs 【第 9 回】 特化命令」
https://magazine.rubyist.net/articles/0017/0017-YarvManiacs.html
に「特化命令」とありました。
YARV はさっぱり分かりませんが,Integer#succ は Integer#next に
はない最適化がなされている,ということなのでしょうか。
なぜ next には同じ最適化がなされていないのでしょうか。
--
5.5@moji.gr.jp