[#120465] [Ruby master Bug#20998] rb_str_locktmp() changes flags of frozen strings and string literals — "Eregon (Benoit Daloze) via ruby-core" <ruby-core@...>
Issue #20998 has been reported by Eregon (Benoit Daloze).
17 messages
2025/01/03
[ruby-core:120721] [Ruby master Bug#19165] Method (with no param) delegation with *, **, and ... is slow
From:
"tenderlovemaking (Aaron Patterson) via ruby-core" <ruby-core@...>
Date:
2025-01-16 21:38:48 UTC
List:
ruby-core #120721
Issue #19165 has been updated by tenderlovemaking (Aaron Patterson).
I reran this benchmark with Ruby 3.5. I think most numbers have improved:
```
$ ruby test.rb
ruby 3.5.0dev (2025-01-16T16:20:06Z master d05f6a9b8f) +PRISM [arm64-darwin=
24]
Warming up --------------------------------------
simple call 3.459M i/100ms
delegate without splat
2.703M i/100ms
delegate with splat 1.343M i/100ms
delegate with splat with name
1.347M i/100ms
delegate with splat and double splat
1.301M i/100ms
delegate with triple dots
2.109M i/100ms
delegate via forwardable
1.125M i/100ms
Calculating -------------------------------------
simple call 34.395M (=B1 0.4%) i/s (29.07 ns/i) - 172.947=
M in 5.028381s
delegate without splat
27.450M (=B1 1.5%) i/s (36.43 ns/i) - 137.830=
M in 5.022175s
delegate with splat 13.360M (=B1 0.5%) i/s (74.85 ns/i) - 67.155=
M in 5.026767s
delegate with splat with name
13.662M (=B1 0.3%) i/s (73.20 ns/i) - 68.678=
M in 5.027114s
delegate with splat and double splat
13.717M (=B1 0.5%) i/s (72.90 ns/i) - 68.952=
M in 5.026767s
delegate with triple dots
20.958M (=B1 0.9%) i/s (47.71 ns/i) - 105.464=
M in 5.032448s
delegate via forwardable
11.273M (=B1 0.7%) i/s (88.71 ns/i) - 57.368=
M in 5.089149s
Comparison:
simple call: 34394553.5 i/s
delegate without splat: 27450367.6 i/s - 1.25x slower
delegate with triple dots: 20958426.8 i/s - 1.64x slower
delegate with splat and double splat: 13717235.5 i/s - 2.51x slower
delegate with splat with name: 13661705.2 i/s - 2.52x slower
delegate with splat: 13359936.0 i/s - 2.57x slower
delegate via forwardable: 11273246.8 i/s - 3.05x slower
```
I think we could probably do something to speed up anonymous `*` and anonym=
ous `**`, but I'm not sure why use those and not `...`. I guess there is a=
reason, but I also bet most cases in Rails that use anonymous `*` and `**`=
can be changed to use `...` without any impact to behavior.
----------------------------------------
Bug #19165: Method (with no param) delegation with *, **, and ... is slow
https://bugs.ruby-lang.org/issues/19165#change-111554
* Author: matsuda (Akira Matsuda)
* Status: Open
* ruby -v: ruby 3.2.0dev (2022-12-01T08:05:41Z master 4e68b59431) +YJIT [ar=
m64-darwin21]
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
I found that method delegation via Forwardable is much slower than normal m=
ethod call when delegating a method that does not take parameters.
Here's a benchmark that explains what I mean.
```
require 'forwardable'
require 'pp'
require 'benchmark/ips'
class Obj
extend Forwardable
attr_accessor :other
def initialize
@other =3D Other.new
end
def foo_without_splat
@other.foo
end
def foo_with_splat(*)
@other.foo(*)
end
def foo_with_splat_with_name(*args)
@other.foo(*args)
end
def foo_with_splat_and_double_splat(*, **)
@other.foo(*, **)
end
def foo_with_triple_dots(...)
@other.foo(...)
end
delegate :foo =3D> :@other
end
class Other
def foo() end
end
o =3D Obj.new
Benchmark.ips do |x|
x.report 'simple call' do
o.other.foo
end
x.report 'delegate without splat' do
o.foo_without_splat
end
x.report 'delegate with splat' do
o.foo_with_splat
end
x.report 'delegate with splat with name' do
o.foo_with_splat_with_name
end
x.report 'delegate with splat and double splat' do
o.foo_with_splat_and_double_splat
end
x.report 'delegate with triple dots' do
o.foo_with_triple_dots
end
x.report 'delegate via forwardable' do
o.foo
end
end
(result)
simple call 38.918M (=B1 0.9%) i/s - 194.884M
delegate without splat
31.933M (=B1 1.6%) i/s - 159.611M
delegate with splat 10.269M (=B1 1.6%) i/s - 51.631M
delegate with splat with name
9.888M (=B1 1.0%) i/s - 49.588M
delegate with splat and double splat
4.117M (=B1 0.9%) i/s - 20.696M
delegate with triple dots
4.169M (=B1 0.9%) i/s - 20.857M
delegate via forwardable
9.204M (=B1 2.1%) i/s - 46.295M
```
It shows that Method delegation with a splat is 3-4 times slower (regardles=
s of whether the parameter is named or not), and delegation with a triple-d=
ot literal is 9-10 times slower than a method delegation without an argumen=
t.
This may be because calling a method taking a splat always assigns an Array=
object even when no actual argument was given, and calling a method taking=
triple-dots assigns five Array objects and two Hash objects (this is equiv=
alent to `*, **`).
Are there any chance reducing these object assignments and making them fast=
er? My concern is that the Rails framework heavily uses this kind of method=
delegations, and presumably it causes unignorable performance overhead.
--=20
https://bugs.ruby-lang.org/
______________________________________________
ruby-core mailing list -- ruby-core@ml.ruby-lang.org
To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.rub=
y-lang.org/