[#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:120722] [Ruby master Bug#19165] Method (with no param) delegation with *, **, and ... is slow
From:
"jeremyevans0 (Jeremy Evans) via ruby-core" <ruby-core@...>
Date:
2025-01-16 22:26:39 UTC
List:
ruby-core #120722
Issue #19165 has been updated by jeremyevans0 (Jeremy Evans).
tenderlovemaking (Aaron Patterson) wrote in #note-6:
> I think we could probably do something to speed up anonymous `*` and anon=
ymous `**`, 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.
tldr; `...` is useful if you are forward everything, `*`, `**`, and `&` are=
useful if you want to be selective regarding what you are forwarding.
You can only use `...` if you are forwarding everything other than the prec=
eding positional arguments. There are cases where you need to use `*` and `=
**` and cannot use `...` (though they may be less common than cases where y=
ou can use `...`):
```ruby
def a(*, **nil); b(*) end # do not accept keyword arguments
def a(*, c: true) b(*) if c end # only accept specific keyword arguments
def a(**); b(**) end # do not accept positional arguments
def a(c, **); b(**) if c end # only accept specific positional argum=
ent
def a(*, **); b(*, **) if yield end # do not forward block
```
----------------------------------------
Bug #19165: Method (with no param) delegation with *, **, and ... is slow
https://bugs.ruby-lang.org/issues/19165#change-111555
* 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 -- [email protected]
To unsubscribe send an email to [email protected]
ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.rub=
y-lang.org/