From aeb7ece081eb3909efa0b14d2086e4efbb727b09 Mon Sep 17 00:00:00 2001 From: Watson Date: Wed, 14 Aug 2024 18:12:30 +0900 Subject: [PATCH] Use UnboundMethod#bind_call method instead to improve performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UnboundMethod#bind_call method had been introduced at Ruby 2.7 that it aims to improve performance. Ref. https://bugs.ruby-lang.org/issues/15955 ### environment - Linux - Manjaro Linux x86_64 - Kernel: 6.9.12-1-MANJARO - CPU: Intel i9-14900 (32) @ 5.500GHz - Compiler: gcc 14.1.1 - Ruby: ruby 3.3.4 (2024-07-09 revision be1089c8ec) [x86_64-linux] ### micro benchmark code ```ruby require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'benchmark-ips' end class Foo def foo end end meth = Foo.instance_method(:foo) obj = Foo.new Benchmark.ips do |x| x.report("bind.call") { meth.bind(obj).call } x.report("bind_call") { meth.bind_call(obj) } x.compare! end ``` ### result ``` $ ruby bind_call.rb ruby 3.3.4 (2024-07-09 revision be1089c8ec) [x86_64-linux] Warming up -------------------------------------- bind.call 766.396k i/100ms bind_call 1.651M i/100ms Calculating ------------------------------------- bind.call 7.967M (± 3.4%) i/s - 39.853M in 5.008135s bind_call 16.881M (± 4.8%) i/s - 85.852M in 5.097269s Comparison: bind_call: 16880585.1 i/s bind.call: 7966891.3 i/s - 2.12x slower ``` Signed-off-by: Watson --- lib/fluent/compat/call_super_mixin.rb | 6 +++--- lib/fluent/compat/propagate_default.rb | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/fluent/compat/call_super_mixin.rb b/lib/fluent/compat/call_super_mixin.rb index 24be38e112..2db2ced679 100644 --- a/lib/fluent/compat/call_super_mixin.rb +++ b/lib/fluent/compat/call_super_mixin.rb @@ -41,7 +41,7 @@ def self.prepended(klass) def start super unless self.started? - @@_super_start[self.class].bind(self).call + @@_super_start[self.class].bind_call(self) # #super will reset logdev (especially in test), so this warn should be after calling it log.warn "super was not called in #start: called it forcedly", plugin: self.class end @@ -51,7 +51,7 @@ def before_shutdown super unless self.before_shutdown? log.warn "super was not called in #before_shutdown: calling it forcedly", plugin: self.class - @@_super_before_shutdown[self.class].bind(self).call + @@_super_before_shutdown[self.class].bind_call(self) end end @@ -68,7 +68,7 @@ def shutdown super unless self.shutdown? log.warn "super was not called in #shutdown: calling it forcedly", plugin: self.class - @@_super_shutdown[self.class].bind(self).call + @@_super_shutdown[self.class].bind_call(self) end end end diff --git a/lib/fluent/compat/propagate_default.rb b/lib/fluent/compat/propagate_default.rb index 71f57e372f..dc42f6e14a 100644 --- a/lib/fluent/compat/propagate_default.rb +++ b/lib/fluent/compat/propagate_default.rb @@ -33,25 +33,25 @@ module ClassMethods CONFIGURABLE_CLASS_METHODS = Fluent::Configurable::ClassMethods def config_param(name, type = nil, **kwargs, &block) - CONFIGURABLE_CLASS_METHODS.instance_method(:config_param).bind(self).call(name, type, **kwargs, &block) + CONFIGURABLE_CLASS_METHODS.instance_method(:config_param).bind_call(self, name, type, **kwargs, &block) pparams = propagate_default_params if kwargs.has_key?(:default) && pparams[name.to_s] newer = pparams[name.to_s].to_sym overridden_default_value = kwargs[:default] - CONFIGURABLE_CLASS_METHODS.instance_method(:config_section).bind(self).call(:buffer) do + CONFIGURABLE_CLASS_METHODS.instance_method(:config_section).bind_call(self, :buffer) do config_set_default newer, overridden_default_value end end end def config_set_default(name, defval) - CONFIGURABLE_CLASS_METHODS.instance_method(:config_set_default).bind(self).call(name, defval) + CONFIGURABLE_CLASS_METHODS.instance_method(:config_set_default).bind_call(self, name, defval) pparams = propagate_default_params if pparams[name.to_s] newer = pparams[name.to_s].to_sym - CONFIGURABLE_CLASS_METHODS.instance_method(:config_section).bind(self).call(:buffer) do + CONFIGURABLE_CLASS_METHODS.instance_method(:config_section).bind_call(self, :buffer) do self.config_set_default newer, defval end end