Skip to content
  • Jean Boussier's avatar
    bbdcfc07
    Optimize `Object#instance_values` · bbdcfc07
    Jean Boussier authored
    `Array#to_h` is substantially faster than `Hash::[]` because having a stricter interface
    it can preallocate the hash with the right size.
    
    We also freeze the strings early so that `Hash#[]` doesn't have to dup them.
    
    ```ruby
    require 'benchmark/ips'
    
    puts RUBY_VERSION
    
    class Object
      def instance_values
        Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
      end
    
      def instance_values_opt
        instance_variables.to_h do |ivar|
          [ivar[1..-1].freeze, instance_variable_get(ivar)]
        end
      end
    end
    
    SMALL = Object.new
    2.times { |i| SMALL.instance_variable_set(:"@variable_#{i}", i) }
    
    LARGE = Object.new
    15.times { |i| LARGE.instance_variable_set(:"@variable_#{i}", i) }
    
    {
      'SMALL' => SMALL,
      'LARGE' => LARGE
    }.each do |size, object|
      puts "=== #{size} ==="
      Benchmark.ips do |x|
        x.report('original') { object.instance_values }
        x.report('patched') { object.instance_values_opt }
        x.compare!
      end
    end
    ```
    
    ```
    3.1.0
    === SMALL ===
    Warming up --------------------------------------
                original    95.429k i/100ms
                 patched   116.046k i/100ms
    Calculating -------------------------------------
                original    963.241k (± 1.3%) i/s -      4.867M in   5.053433s
                 patched      1.246M (± 0.8%) i/s -      6.266M in   5.031372s
    
    Comparison:
                 patched:  1245570.0 i/s
                original:   963240.9 i/s - 1.29x  (± 0.00) slower
    
    === LARGE ===
    Warming up --------------------------------------
                original    15.799k i/100ms
                 patched    18.285k i/100ms
    Calculating -------------------------------------
                original    157.163k (± 1.3%) i/s -    789.950k in   5.027176s
                 patched    181.587k (± 1.1%) i/s -    914.250k in   5.035344s
    
    Comparison:
                 patched:   181587.4 i/s
                original:   157163.4 i/s - 1.16x  (± 0.00) slower
    ```
    bbdcfc07
    Optimize `Object#instance_values`
    Jean Boussier authored
    `Array#to_h` is substantially faster than `Hash::[]` because having a stricter interface
    it can preallocate the hash with the right size.
    
    We also freeze the strings early so that `Hash#[]` doesn't have to dup them.
    
    ```ruby
    require 'benchmark/ips'
    
    puts RUBY_VERSION
    
    class Object
      def instance_values
        Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
      end
    
      def instance_values_opt
        instance_variables.to_h do |ivar|
          [ivar[1..-1].freeze, instance_variable_get(ivar)]
        end
      end
    end
    
    SMALL = Object.new
    2.times { |i| SMALL.instance_variable_set(:"@variable_#{i}", i) }
    
    LARGE = Object.new
    15.times { |i| LARGE.instance_variable_set(:"@variable_#{i}", i) }
    
    {
      'SMALL' => SMALL,
      'LARGE' => LARGE
    }.each do |size, object|
      puts "=== #{size} ==="
      Benchmark.ips do |x|
        x.report('original') { object.instance_values }
        x.report('patched') { object.instance_values_opt }
        x.compare!
      end
    end
    ```
    
    ```
    3.1.0
    === SMALL ===
    Warming up --------------------------------------
                original    95.429k i/100ms
                 patched   116.046k i/100ms
    Calculating -------------------------------------
                original    963.241k (± 1.3%) i/s -      4.867M in   5.053433s
                 patched      1.246M (± 0.8%) i/s -      6.266M in   5.031372s
    
    Comparison:
                 patched:  1245570.0 i/s
                original:   963240.9 i/s - 1.29x  (± 0.00) slower
    
    === LARGE ===
    Warming up --------------------------------------
                original    15.799k i/100ms
                 patched    18.285k i/100ms
    Calculating -------------------------------------
                original    157.163k (± 1.3%) i/s -    789.950k in   5.027176s
                 patched    181.587k (± 1.1%) i/s -    914.250k in   5.035344s
    
    Comparison:
                 patched:   181587.4 i/s
                original:   157163.4 i/s - 1.16x  (± 0.00) slower
    ```
Loading