Skip to content
  • Koichi Sasada's avatar
    cfd7729c
    use inline cache for refinements · cfd7729c
    Koichi Sasada authored
    From Ruby 3.0, refined method invocations are slow because
    resolved methods are not cached by inline cache because of
    conservertive strategy. However, `using` clears all caches
    so that it seems safe to cache resolved method entries.
    
    This patch caches resolved method entries in inline cache
    and clear all of inline method caches when `using` is called.
    
    fix [Bug #18572]
    
    ```ruby
     # without refinements
    
    class C
      def foo = :C
    end
    
    N = 1_000_000
    
    obj = C.new
    require 'benchmark'
    Benchmark.bm{|x|
      x.report{N.times{
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
      }}
    }
    
    _END__
                  user     system      total        real
    master    0.362859   0.002544   0.365403 (  0.365424)
    modified  0.357251   0.000000   0.357251 (  0.357258)
    ```
    
    ```ruby
     # with refinment but without using
    
    class C
      def foo = :C
    end
    
    module R
      refine C do
        def foo = :R
      end
    end
    
    N = 1_000_000
    
    obj = C.new
    require 'benchmark'
    Benchmark.bm{|x|
      x.report{N.times{
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
      }}
    }
    __END__
                   user     system      total        real
    master     0.957182   0.000000   0.957182 (  0.957212)
    modified   0.359228   0.000000   0.359228 (  0.359238)
    ```
    
    ```ruby
     # with using
    
    class C
      def foo = :C
    end
    
    module R
      refine C do
        def foo = :R
      end
    end
    
    N = 1_000_000
    
    using R
    
    obj = C.new
    require 'benchmark'
    Benchmark.bm{|x|
      x.report{N.times{
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
      }}
    }
    cfd7729c
    use inline cache for refinements
    Koichi Sasada authored
    From Ruby 3.0, refined method invocations are slow because
    resolved methods are not cached by inline cache because of
    conservertive strategy. However, `using` clears all caches
    so that it seems safe to cache resolved method entries.
    
    This patch caches resolved method entries in inline cache
    and clear all of inline method caches when `using` is called.
    
    fix [Bug #18572]
    
    ```ruby
     # without refinements
    
    class C
      def foo = :C
    end
    
    N = 1_000_000
    
    obj = C.new
    require 'benchmark'
    Benchmark.bm{|x|
      x.report{N.times{
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
      }}
    }
    
    _END__
                  user     system      total        real
    master    0.362859   0.002544   0.365403 (  0.365424)
    modified  0.357251   0.000000   0.357251 (  0.357258)
    ```
    
    ```ruby
     # with refinment but without using
    
    class C
      def foo = :C
    end
    
    module R
      refine C do
        def foo = :R
      end
    end
    
    N = 1_000_000
    
    obj = C.new
    require 'benchmark'
    Benchmark.bm{|x|
      x.report{N.times{
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
      }}
    }
    __END__
                   user     system      total        real
    master     0.957182   0.000000   0.957182 (  0.957212)
    modified   0.359228   0.000000   0.359228 (  0.359238)
    ```
    
    ```ruby
     # with using
    
    class C
      def foo = :C
    end
    
    module R
      refine C do
        def foo = :R
      end
    end
    
    N = 1_000_000
    
    using R
    
    obj = C.new
    require 'benchmark'
    Benchmark.bm{|x|
      x.report{N.times{
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
        obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
      }}
    }
Loading