Skip to content

Improve performance of Gitlab::Utils::InlineHash

We can actually be 1.2 to 4x faster with a small tweak. But overall this is good enough, so let's follow-up this at a later stage.

Benchmarks for small

Calculating -------------------------------------
         small recur    12.311k i/100ms
  small iter unshift    20.838k i/100ms
small iter unshift no prefix
                        23.162k i/100ms
-------------------------------------------------
         small recur    143.455k (± 7.5%) i/s -    714.038k
  small iter unshift    239.523k (± 5.5%) i/s -      1.209M
small iter unshift no prefix
                        298.997k (± 8.2%) i/s -      1.506M

Comparison:
small iter unshift no prefix:   298997.0 i/s
  small iter unshift:   239522.5 i/s - 1.25x slower
         small recur:   143455.3 i/s - 2.08x slower

================================================================================

Benchmarks for medium

Calculating -------------------------------------
        medium recur   946.000  i/100ms
 medium iter unshift     1.723k i/100ms
medium iter unshift no prefix
                         5.028k i/100ms
-------------------------------------------------
        medium recur      9.918k (± 6.3%) i/s -     50.138k
 medium iter unshift     17.232k (± 8.4%) i/s -     86.150k
medium iter unshift no prefix
                         57.738k (± 3.5%) i/s -    291.624k

Comparison:
medium iter unshift no prefix:    57738.2 i/s
 medium iter unshift:    17232.1 i/s - 3.35x slower
        medium recur:     9917.5 i/s - 5.82x slower

================================================================================

Benchmarks for large

Calculating -------------------------------------
         large recur    50.000  i/100ms
  large iter unshift    78.000  i/100ms
large iter unshift no prefix
                       316.000  i/100ms
-------------------------------------------------
         large recur    515.679  (± 3.3%) i/s -      2.600k
  large iter unshift    785.427  (± 1.9%) i/s -      3.978k
large iter unshift no prefix
                          3.199k (± 2.3%) i/s -     16.116k

Comparison:
large iter unshift no prefix:     3198.9 i/s
  large iter unshift:      785.4 i/s - 4.07x slower
         large recur:      515.7 i/s - 6.20x slower

================================================================================

Benchmarks for huge

Calculating -------------------------------------
          huge recur     9.000  i/100ms
   huge iter unshift    12.000  i/100ms
huge iter unshift no prefix
                        55.000  i/100ms
-------------------------------------------------
          huge recur     90.355  (± 8.9%) i/s -    450.000 
   huge iter unshift    143.729  (± 7.7%) i/s -    720.000 
huge iter unshift no prefix
                        576.654  (± 5.4%) i/s -      2.915k

Comparison:
huge iter unshift no prefix:      576.7 i/s
   huge iter unshift:      143.7 i/s - 4.01x slower
          huge recur:       90.4 i/s - 6.38x slower

================================================================================

The following discussions from !16441 (merged) should be addressed:

  • @tkuah started a discussion:

      describe '.merge_keys!' do
  • @tkuah started a discussion:

            pairs = 
              if prefix
                hash.map { |key, value| ["#{base_prefix}#{key}", value] }
              else
                hash.to_a
              end

    If prefix is nil, we can save ourselves iterating the hash twice. Or we can get rid of the prefix: if not needed.

Edited by Vitali Tatarintev