* [ruby-dev:50411] [Ruby trunk Feature#14329] Speedup `block.call` where `block` is passed block parameter.
[not found] <redmine.issue-14329.20180107164950@ruby-lang.org>
@ 2018-01-07 16:49 ` ko1
2018-01-07 16:57 ` [ruby-dev:50412] [Ruby trunk Feature#14329][Closed] " ko1
1 sibling, 0 replies; 2+ messages in thread
From: ko1 @ 2018-01-07 16:49 UTC (permalink / raw)
To: ruby-dev
Issue #14329 has been reported by ko1 (Koichi Sasada).
----------------------------------------
Feature #14329: Speedup `block.call` where `block` is passed block parameter.
https://bugs.ruby-lang.org/issues/14329
* Author: ko1 (Koichi Sasada)
* Status: Open
* Priority: Normal
* Assignee: ko1 (Koichi Sasada)
* Target version: 2.6
----------------------------------------
# abstract
Speedup `block.call` where `block` is passed block parameter with a special object named "proxyblock" which responds to `call` and invoke passed block.
# background
Ruby 2.5 improved performance of passing a passed block parameter by lazy Proc creation ([Feature #14045]).
However, `block.call` (`block` is a passed block parameter) is not optimized and need to create a `Proc` object immediately.
# proposal
We need to make Proc creation lazily for performance. There are several way to achieve it, but I propose to use special object named "blockproxy" object.
This is a pseudo code to use it:
```ruby
# block is given block parameter
block.call(1, 2, 3)
#=> translate at compile time
if block is not modified and
block is ISeq/IFunc block
tmp = blockproxy
else
tmp = block # create Proc and so on
end
tmp.call(1, 2, 3)
```
`blockproxy.call` invoke given block if `Proc#call` is not redefined, otherwise make a Proc and call `Proc#call` as usual.
Advantage of this method is we can also use this technique with the safe navigation operator (`block&.call`).
If block is not given, then `tmp` will be `nil`, and no method dispatched with `&.`.
Note that this technique depends on the assumption "we can't access to the evaluated receiver just before method dispatch". We don't/can't access `blockproxy` object at method dispatch, and no compatibility issue.
# evaluation
Using https://github.com/k0kubun/benchmark_driver
```
prelude: |
def block_yield
yield
end
def bp_yield &b
yield
end
def bp_call &b
b.call
end
def bp_safe_call &b
b&.call
end
benchmark:
- block_yield{}
- bp_yield{}
- bp_call{}
- bp_safe_call{}
- bp_safe_call
```
Result:
```
Warming up --------------------------------------
block_yield{} 1.298M i/100ms
bp_yield{} 1.177M i/100ms
bp_call{} 447.723k i/100ms
bp_safe_call{} 413.261k i/100ms
bp_safe_call 2.955M i/100ms
Calculating -------------------------------------
trunk modified
block_yield{} 20.672M 20.808M i/s - 51.933M in 2.512265s 2.495806s
bp_yield{} 16.294M 16.220M i/s - 47.099M in 2.890459s 2.903797s
bp_call{} 5.626M 14.752M i/s - 17.909M in 3.182966s 1.213976s # x2.62
bp_safe_call{} 5.555M 14.557M i/s - 16.530M in 2.975892s 1.135586s # x2.62
bp_safe_call 31.339M 23.561M i/s - 118.184M in 3.771157s 5.016200s
```
The patch is here:
https://gist.github.com/ko1/d8a1a9d92075b27a8e95ca528cc57fd2
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 2+ messages in thread
* [ruby-dev:50412] [Ruby trunk Feature#14329][Closed] Speedup `block.call` where `block` is passed block parameter.
[not found] <redmine.issue-14329.20180107164950@ruby-lang.org>
2018-01-07 16:49 ` [ruby-dev:50411] [Ruby trunk Feature#14329] Speedup `block.call` where `block` is passed block parameter ko1
@ 2018-01-07 16:57 ` ko1
1 sibling, 0 replies; 2+ messages in thread
From: ko1 @ 2018-01-07 16:57 UTC (permalink / raw)
To: ruby-dev
Issue #14329 has been updated by ko1 (Koichi Sasada).
Status changed from Open to Closed
move to ruby-core.
----------------------------------------
Feature #14329: Speedup `block.call` where `block` is passed block parameter.
https://bugs.ruby-lang.org/issues/14329#change-69403
* Author: ko1 (Koichi Sasada)
* Status: Closed
* Priority: Normal
* Assignee: ko1 (Koichi Sasada)
* Target version: 2.6
----------------------------------------
# abstract
Speedup `block.call` where `block` is passed block parameter with a special object named "proxyblock" which responds to `call` and invoke passed block.
# background
Ruby 2.5 improved performance of passing a passed block parameter by lazy Proc creation ([Feature #14045]).
However, `block.call` (`block` is a passed block parameter) is not optimized and need to create a `Proc` object immediately.
# proposal
We need to make Proc creation lazily for performance. There are several way to achieve it, but I propose to use special object named "blockproxy" object.
This is a pseudo code to use it:
```ruby
# block is given block parameter
block.call(1, 2, 3)
#=> translate at compile time
if block is not modified and
block is ISeq/IFunc block
tmp = blockproxy
else
tmp = block # create Proc and so on
end
tmp.call(1, 2, 3)
```
`blockproxy.call` invoke given block if `Proc#call` is not redefined, otherwise make a Proc and call `Proc#call` as usual.
Advantage of this method is we can also use this technique with the safe navigation operator (`block&.call`).
If block is not given, then `tmp` will be `nil`, and no method dispatched with `&.`.
Note that this technique depends on the assumption "we can't access to the evaluated receiver just before method dispatch". We don't/can't access `blockproxy` object at method dispatch, and no compatibility issue.
# evaluation
Using https://github.com/k0kubun/benchmark_driver
```
prelude: |
def block_yield
yield
end
def bp_yield &b
yield
end
def bp_call &b
b.call
end
def bp_safe_call &b
b&.call
end
benchmark:
- block_yield{}
- bp_yield{}
- bp_call{}
- bp_safe_call{}
- bp_safe_call
```
Result:
```
Warming up --------------------------------------
block_yield{} 1.298M i/100ms
bp_yield{} 1.177M i/100ms
bp_call{} 447.723k i/100ms
bp_safe_call{} 413.261k i/100ms
bp_safe_call 2.955M i/100ms
Calculating -------------------------------------
trunk modified
block_yield{} 20.672M 20.808M i/s - 51.933M in 2.512265s 2.495806s
bp_yield{} 16.294M 16.220M i/s - 47.099M in 2.890459s 2.903797s
bp_call{} 5.626M 14.752M i/s - 17.909M in 3.182966s 1.213976s # x2.62
bp_safe_call{} 5.555M 14.557M i/s - 16.530M in 2.975892s 1.135586s # x2.62
bp_safe_call 31.339M 23.561M i/s - 118.184M in 3.771157s 5.016200s
```
The patch is here:
https://gist.github.com/ko1/d8a1a9d92075b27a8e95ca528cc57fd2
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2018-01-07 16:57 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <redmine.issue-14329.20180107164950@ruby-lang.org>
2018-01-07 16:49 ` [ruby-dev:50411] [Ruby trunk Feature#14329] Speedup `block.call` where `block` is passed block parameter ko1
2018-01-07 16:57 ` [ruby-dev:50412] [Ruby trunk Feature#14329][Closed] " ko1
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).