Create a gist now

Instantly share code, notes, and snippets.

Benchmark of using different methods to convert complex Mash to Hash

Using the following Gem versions:

  • benchmark-ips (2.1.0)
  • chef (11.16.4), which includes:
    • erubis (2.7.0)
    • json (1.8.1)

Ruby 1.9.3:

Calculating -------------------------------------
         monkeypatch    75.000  i/100ms
      mash2json2yaml    73.000  i/100ms
-------------------------------------------------
         monkeypatch    745.984  (± 9.9%) i/s -      3.750k
      mash2json2yaml    761.028  (± 7.9%) i/s -      3.796k

Comparison:
      mash2json2yaml:      761.0 i/s
         monkeypatch:      746.0 i/s - 1.02x slower

Ruby 2.1.5:

Calculating -------------------------------------
         monkeypatch    88.000  i/100ms
      mash2json2yaml    86.000  i/100ms
-------------------------------------------------
         monkeypatch    884.203  (± 4.0%) i/s -      4.488k
      mash2json2yaml    865.697  (± 3.8%) i/s -      4.386k

Comparison:
         monkeypatch:      884.2 i/s
      mash2json2yaml:      865.7 i/s - 1.02x slower
require 'benchmark/ips'
require 'chef'
require 'erubis'
HASHDATA = {
'conf' => [
{
'exclude' => [
{
'domain' => 'evil_domain'
}
],
'include' => {
'attribute' => {
'bytesReceived' => { 'metric_type' => 'counter', 'alias' => 'tomcat.bytes_rcvd' },
'maxThreads' => { 'metric_type' => 'gauge', 'alias' => 'tomcat.threads.max' }
},
'bean' => 'tomcat_bean',
'domain' => 'domain0',
'type' => 'ThreadPool'
},
'include' => {
'attributes' => [
'BloomFilterDiskSpaceUsed',
'Capacity'
],
'bean_name' => 'com.datadoghq.test:type=BeanType,tag1=my_bean_name',
'domain' => 'org.apache.cassandra.db',
'foo' => 'bar'
}
}
],
'extra_key' => 'extra_val',
'host' => 'localhost',
'port' => 9999
}
# Simulate Attribute loading by creating the Mash directly
MASH1 = Chef::Node::ImmutableMash.new(HASHDATA)
MASH2 = Chef::Node::ImmutableMash.new(HASHDATA)
@mash_array = Chef::Node::ImmutableArray.new [MASH1, MASH2]
# Monkeypatching of Chef classes to provide `deep` class conversion
class Chef
class Node
class ImmutableMash
def deep_to_hash
h = {}
self.each do |k,v|
if v.respond_to?('deep_to_hash')
h[k] = v.deep_to_hash
elsif v.respond_to?('deep_to_a')
h[k] = v.deep_to_a
else
h[k] = v
end
end
return h
end
end
class ImmutableArray
def deep_to_a
a = []
self.each do |v|
if v.respond_to?('deep_to_hash')
a << v.deep_to_hash
elsif v.respond_to?('deep_to_a')
a << v.deep_to_a
else
a << v
end
end
return a
end
end
end
end
# Common render method for benchmarks
def render(template)
eruby = Erubis::Eruby.new(template)
output = eruby.evaluate(Erubis::Context)
end
def monkeypatch
render("<%= YAML.dump({ 'instances' => #{@mash_array.deep_to_a} }) %>")
end
def mash2json2yaml
render("<%= JSON.parse(({ 'instances' => #{@mash_array}.to_a }).to_json).to_yaml %>")
end
Benchmark.ips do |x|
x.report('monkeypatch') { monkeypatch }
x.report('mash2json2yaml') { mash2json2yaml }
x.compare!
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment