Feature #13602
closedOptimize instance variable access if $VERBOSE is not true when compiling
Description
This patch optimizes instance variable lookup in the case the $VERBOSE
is not true when compiling. If $VERBOSE is not true when compiling
code, it makes the instance variable access use an optimized VM
instruction that does not check $VERBOSE at runtime.
This does not change the behavior if $VERBOSE is not changed at runtime,
only when $VERBOSE is not true when compiling the code, but is true when
running it. In the case where $VERBOSE is not true when compiling and
true at runtime, this patch makes ruby no longer emit the warning
message.
Using a similar benchmark as #10396:
require 'benchmark/ips'
class A
def initialize
@c = @d = @e = @f = nil
end
def b
@c || @d || @e || @f
end
end
Benchmark.ips do |x|
x.report("A.new.b"){A.new.b}
x.report("A.allocate.b"){A.allocate.b}
end
Before Patch:
A.new.b 347.380k (_ 1.7%) i/s - 1.741M
A.allocate.b 862.884k (_ 0.4%) i/s - 4.317M
A.new.b 338.830k (_ 1.7%) i/s - 1.706M
A.allocate.b 848.036k (_ 0.4%) i/s - 4.254M
A.new.b 344.167k (_ 1.7%) i/s - 1.731M
A.allocate.b 826.183k (_ 0.4%) i/s - 4.138M
After Patch:
A.new.b 350.251k (_ 1.7%) i/s - 1.753M
A.allocate.b 900.666k (_ 0.7%) i/s - 4.512M
A.new.b 349.868k (_ 1.7%) i/s - 1.760M
A.allocate.b 898.292k (_ 0.4%) i/s - 4.505M
A.new.b 349.690k (_ 1.7%) i/s - 1.751M
A.allocate.b 888.524k (_ 0.6%) i/s - 4.444M
So about a 1-2% increase in the case where instance variables are
already initialized, and about 5-7% increase in the case where
instance variables are not initialized.
Files
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
It doesn't look nice to assume $VERBOSE
doesn't change.
And seems that benchmark includes allocation and initialization.
Updated by jeremyevans0 (Jeremy Evans) over 7 years ago
OK, here's a slightly revised benchmark that just measures
instance variable access without allocation:
require 'benchmark/ips'
$stderr.reopen('/dev/null')
class A
def initialize
@c = @d = @e = @f = nil
end
def b
@c || @d || @e || @f
end
end
n = A.new
a = A.allocate
Benchmark.ips do |x|
x.report("new.b"){n.b}
x.report("allocate.b"){a.b}
end
Before:
new.b 1.597M (_ 0.3%) i/s - 7.998M
allocate.b 1.553M (_ 0.8%) i/s - 7.782M
new.b 1.635M (_ 0.7%) i/s - 8.196M
allocate.b 1.590M (_ 0.5%) i/s - 7.970M
new.b 1.607M (_ 0.2%) i/s - 8.051M
allocate.b 1.552M (_ 0.3%) i/s - 7.776M
After:
new.b 1.703M (_ 0.9%) i/s - 8.521M
allocate.b 1.788M (_ 0.3%) i/s - 8.935M
new.b 1.773M (_ 0.7%) i/s - 8.884M
allocate.b 1.812M (_ 0.2%) i/s - 9.062M
new.b 1.772M (_ 1.2%) i/s - 8.875M
allocate.b 1.809M (_ 0.3%) i/s - 9.046M
So about an 8% improvement for initialized instance variables,
and 14% improvement for uninitialized instance variables.
I do realize that this breaks backwards compatibility slightly.
If the performance benefits do not justify that, this can be
closed.
Updated by ko1 (Koichi Sasada) about 7 years ago
- Status changed from Open to Feedback
It seems 5% can not justify this kind of optimization.
We can use your technique when we revert all of optimized instructions when $VERBOSE was changed. But I'm not sure this kind of modification is valuable than implementation cost (it can be).
Updated by jeremyevans0 (Jeremy Evans) about 7 years ago
- Status changed from Feedback to Rejected
ko1 (Koichi Sasada) wrote:
It seems 5% can not justify this kind of optimization.
We can use your technique when we revert all of optimized instructions when $VERBOSE was changed. But I'm not sure this kind of modification is valuable than implementation cost (it can be).
I think this can be rejected then. Reverting the optimized instructions would require compiling both the unoptimized version and the optimized version and keeping both in memory, or recompiling on a change to $VERBOSE, neither of which seems like a reasonable approach considering the modest performance improvement.