【一人 bugs.ruby Advent Calendar 2021】[Bug #18293] Time.at in master branch was 25% slower then Ruby 3.0【18日目】

一人 bugs.ruby Advent Calendar 2021 18日目の記事になります。
今日は Time.at のパフォーマンスが遅くなった話です。

[Bug #18293] Time.at in master branch was 25% slower then Ruby 3.0

Time.at3.0.23.1.0-dev と比較して 25% 遅くなったというバグ報告です。
チケットに書かれている比較は以下の通り。

# Test code
require 'benchmark/ips'

Benchmark.ips do |x|
  x.report('Time.at') { Time.at(0) }
end
# Ruby 3.0.2
$ ruby -v time.rb
ruby 3.1.0dev (2021-11-08T13:15:21Z master bd2674ad33) [arm64-darwin21]
Warming up --------------------------------------
             Time.at   614.843k i/100ms
Calculating -------------------------------------
             Time.at      6.190M (± 0.3%) i/s -     31.357M in   5.065559s
# Ruby 3.0.1-dev
$ ruby -v time.rb
ruby 3.1.0dev (2021-11-08T13:15:21Z master bd2674ad33) [arm64-darwin21]
Warming up --------------------------------------
             Time.at   614.843k i/100ms
Calculating -------------------------------------
             Time.at      6.190M (± 0.3%) i/s -     31.357M in   5.065559s

これは Time.at の実装を time.c から timev.rb に移動させたのが原因らしい。
以下が当時の実装になります。

def self.at(time, subsec = false, unit = :microsecond, in: nil)
  Primitive.time_s_at(time, subsec, unit, Primitive.arg!(:in))
end

具体的にはその Ruby 実装でキーワード引数を渡していない場合も Primitive.arg!(:in) が呼ばれてしまっていたのがネックっぽい? 最終的には Primitive.mandatory_only? という特殊なメソッドが追加されて条件分岐して高速化されました。

def self.at(time, subsec = false, unit = :microsecond, in: nil)
  if Primitive.mandatory_only?
    Primitive.time_s_at1(time)
  else
    Primitive.time_s_at(time, subsec, unit, Primitive.arg!(:in))
  end
end