YAML, ZAML, Marshal & JSON benchmark in Ruby
At Defensio, we recently needed to find out how slow YAML was compared to Marshal. We also wanted to know how much faster ZAML, an alternative to YAML, is.
I ran a few benchmarks under 1.8.7 MRI, 1.8.7 REE, 1.9.2 and Rubinius to see how they compare. I also benchmarked to_json to have an order of magnitude. My benchmarks consist of serializing/deserializing a relatively complex Hash (many nested levels). The YAML representation of the Hash is ~3kb.
Conclusions:
- YAML is really slow
- YAML is twice as fast under 1.9.2 vs 1.8.7
- ZAML is much faster than YAML under 1.8.7, but about the same in 1.9.2
- REE (no GC tweaks) isn’t faster in this situation
- Rubinius is ridiculously slow
- Psych under Ruby 1.9.2 is disappointing
Here are the results:
ruby 1.8.7 (2009-06-12 patchlevel 174) [universal-darwin10.0]--------------------------------------------------------------------YAML.load: 0.7924Marshal.load: 0.0742to_yaml: 5.1661ZAML.dump: 1.4574to_json: 0.1152Marshal.dump: 0.0845
ruby 1.8.7 (2010-04-19 patchlevel 253) [i686-darwin10.4.0], MBARI 0x6770, Ruby Enterprise Edition 2010.02--------------------------------------------------------------------YAML.load: 0.7976Marshal.load: 0.0864to_yaml: 4.9012ZAML.dump: 1.3508to_json: 0.0940Marshal.dump: 0.0812
ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-darwin10.5.0]--------------------------------------------------------------------YAML.load: 0.7079YAML.load (Psych): 2.6055Marshal.load: 0.0928to_yaml: 2.1682to_load (Psych): 2.2924ZAML.dump: 5.0259to_json: 0.1133Marshal.dump: 0.0908
rubinius 1.1.1 (1.8.7 4018ebda 2010-11-16 JI) [x86_64-apple-darwin10.5.0]--------------------------------------------------------------------YAML.load: 2.7777Marshal.load: 0.8560to_yaml: 23.5828ZAML.dump: 4.0745to_json: 3.6620Marshal.dump: 3.3797
If you want to benchmark on your machine, here’s the source code. Sorry, I couldn’t include the YAML string as it is confidential data.
require 'rubygems'require 'benchmark'require 'yaml'require 'zaml'require 'json'
yaml_str = <<-eosyaml goes hereeos
h = nilGC.startyaml_load_time = Benchmark::realtime {1000.times { h = YAML.load(yaml_str) }}
GC.startto_yaml_time = Benchmark::realtime {1000.times { h.to_yaml }}
begin YAML::ENGINE.yamler = 'psych' if RUBY_VERSION == "1.9.2"rescue puts "Cannot load Psych. Is libyaml installed? Install it and recompile Ruby." puts "On OS X with RVM, install it with MacPorts and run:" puts "rvm install ruby-1.9.2 -C --with-libyaml-dir=/opt/local" exit 1end
GC.startpsych_load_time = Benchmark::realtime { 1000.times { YAML.load(yaml_str) }}
GC.startto_yaml_psych_time = Benchmark::realtime { 1000.times { h.to_yaml }}
GC.startto_json_time = Benchmark::realtime {1000.times { h.to_json }}
GC.startzaml_dump_time = Benchmark::realtime {1000.times { ZAML.dump(h) }}
marshaled = nilGC.startmarshal_dump_time = Benchmark::realtime {1000.times { marshaled = Marshal.dump(h) }}
GC.startmarshall_load_time = Benchmark::realtime {1000.times { h = Marshal.load(marshaled) }}
puts `ruby -v`puts "--------------------------------------------------------------------"puts "YAML.load:\t\t#{'%.4f' % yaml_load_time}"puts "YAML.load (Psych):\t#{'%.4f' % psych_load_time}" if RUBY_VERSION == "1.9.2"puts "Marshal.load:\t\t#{'%.4f' % marshall_load_time}"puts "to_yaml:\t\t#{'%.4f' % to_yaml_time}"puts "to_load (Psych):\t#{'%.4f' % to_yaml_psych_time}" if RUBY_VERSION == "1.9.2"puts "ZAML.dump:\t\t#{'%.4f' % zaml_dump_time}"puts "to_json:\t\t#{'%.4f' % to_json_time}"puts "Marshal.dump:\t\t#{'%.4f' % marshal_dump_time}"