#!/usr/bin/env ruby # encoding: UTF-8 $: << '.' $: << File.join(File.dirname(__FILE__), "../lib") $: << File.join(File.dirname(__FILE__), "../ext") require 'optparse' require 'perf' require 'oj' require 'json' $verbose = false $iter = 50_000 $with_bignum = false $size = 1 $cache_keys = true $symbol_keys = false opts = OptionParser.new opts.on("-v", "verbose") { $verbose = true } opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i } opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i } opts.on("-b", "with bignum") { $with_bignum = true } opts.on("-k", "no cache") { $cache_keys = false } opts.on("-sym", "symbol keys") { $symbol_keys = true } opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) } files = opts.parse(ARGV) $obj = { 'a' => 'Alpha', # string 'b' => true, # boolean 'c' => 12345, # number 'd' => [ true, [false, [-123456789, nil], 3.9676, ['Something else.', false, 1, nil], nil]], # mix it up array 'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash 'f' => nil, # nil 'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep 'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep } $obj['g'] = 12345678901234567890123456789 if $with_bignum if 0 < $size o = $obj $obj = [] (4 * $size).times do $obj << o end end $json = Oj.dump($obj) $failed = {} # key is same as String used in tests later Oj.default_options = {create_id: '^', create_additions: true, class_cache: true} if $cache_keys Oj.default_options = {cache_keys: true, cache_str: 6, symbol_keys: $symbol_keys} else Oj.default_options = {cache_keys: false, cache_str: -1, symbol_keys: $symbol_keys} end JSON.parser = JSON::Ext::Parser class AllSaj def initialize() end def hash_start(key) end def hash_end(key) end def array_start(key) end def array_end(key) end def add_value(value, key) end end # AllSaj class NoSaj def initialize() end end # NoSaj no_handler = NoSaj.new() all_handler = AllSaj.new() if $verbose puts "json:\n#{$json}\n" end ### Validate ###################### p_val = Oj::Parser.new(:validate) puts '-' * 80 puts "Validate Performance" perf = Perf.new() perf.add('Oj::Parser.validate', 'none') { p_val.parse($json) } perf.add('Oj::Saj.none', 'none') { Oj.saj_parse(no_handler, $json) } perf.run($iter) ### SAJ ###################### p_all = Oj::Parser.new(:saj) p_all.handler = all_handler p_all.cache_keys = $cache_keys p_all.cache_strings = 6 puts '-' * 80 puts "Parse Callback Performance" perf = Perf.new() perf.add('Oj::Parser.saj', 'all') { p_all.parse($json) } perf.add('Oj::Saj.all', 'all') { Oj.saj_parse(all_handler, $json) } perf.run($iter) ### Usual ###################### p_usual = Oj::Parser.new(:usual) p_usual.cache_keys = $cache_keys p_usual.cache_strings = ($cache_keys ? 6 : 0) p_usual.symbol_keys = $symbol_keys puts '-' * 80 puts "Parse Usual Performance" perf = Perf.new() perf.add('Oj::Parser.usual', '') { p_usual.parse($json) } perf.add('Oj::strict_load', '') { Oj.strict_load($json) } perf.add('JSON::Ext', 'parse') { JSON.load($json) } perf.run($iter) ### Usual Objects ###################### # Original Oj follows the JSON gem for creating objects which uses the class # json_create(arg) method. Oj::Parser in usual mode supprts the same but also # handles populating the object variables directly which is faster. class Stuff attr_accessor :alpha, :bravo, :charlie, :delta, :echo, :foxtrot, :golf, :hotel, :india, :juliet def self.json_create(arg) obj = self.new obj.alpha = arg["alpha"] obj.bravo = arg["bravo"] obj.charlie = arg["charlie"] obj.delta = arg["delta"] obj.echo = arg["echo"] obj.foxtrot = arg["foxtrot"] obj.golf = arg["golf"] obj.hotel = arg["hotel"] obj.india = arg["india"] obj.juliet = arg["juliet"] obj end end $obj_json = %|{ "alpha": [0, 1,2,3,4,5,6,7,8,9], "bravo": true, "charlie": 123, "delta": "some string", "echo": null, "^": "Stuff", "foxtrot": false, "golf": "gulp", "hotel": {"x": true, "y": false}, "india": [null, true, 123], "juliet": "junk" }| p_usual = Oj::Parser.new(:usual) p_usual.cache_keys = $cache_keys p_usual.cache_strings = ($cache_keys ? 6 : 0) p_usual.symbol_keys = $symbol_keys p_usual.create_id = '^' p_usual.class_cache = true p_usual.ignore_json_create = true JSON.create_id = '^' puts '-' * 80 puts "Parse Usual Object Performance" perf = Perf.new() perf.add('Oj::Parser.usual', '') { p_usual.parse($obj_json) } perf.add('Oj::compat_load', '') { Oj.compat_load($obj_json) } perf.add('JSON::Ext', 'parse') { JSON.load($obj_json) } perf.run($iter) unless $failed.empty? puts "The following packages were not included for the reason listed" $failed.each { |tag,msg| puts "***** #{tag}: #{msg}" } end