From fbcfbeacbf381d038681c16ddab702711060022e Mon Sep 17 00:00:00 2001 From: Peter Ohler Date: Sat, 3 Jul 2021 21:21:25 -0400 Subject: [PATCH 1/3] Start with strict parsing with cache --- ext/oj/hash.c | 17 +++++++++- ext/oj/hash.h | 2 ++ ext/oj/mimic_json.c | 10 +++--- ext/oj/oj.c | 45 ++++++++++++++++++++++-- ext/oj/oj.h | 2 ++ ext/oj/strict.c | 81 +++++++++++++++++++++++++++++++++++++++----- notes | 11 ++++++ test/perf_strict.rb | 41 ++++++++++------------ test/test_various.rb | 2 ++ 9 files changed, 171 insertions(+), 40 deletions(-) diff --git a/ext/oj/hash.c b/ext/oj/hash.c index c1ea12fe..bc9d4ff4 100644 --- a/ext/oj/hash.c +++ b/ext/oj/hash.c @@ -20,6 +20,8 @@ struct _hash { }; struct _hash class_hash; +struct _hash str_hash; +struct _hash sym_hash; struct _hash intern_hash; // almost the Murmur hash algorithm @@ -64,6 +66,8 @@ static uint32_t hash_calc(const uint8_t *key, size_t len) { void oj_hash_init() { memset(class_hash.slots, 0, sizeof(class_hash.slots)); + memset(str_hash.slots, 0, sizeof(str_hash.slots)); + memset(sym_hash.slots, 0, sizeof(sym_hash.slots)); memset(intern_hash.slots, 0, sizeof(intern_hash.slots)); } @@ -117,7 +121,18 @@ oj_class_hash_get(const char *key, size_t len, VALUE **slotp) { return hash_get(&class_hash, key, len, slotp, Qnil); } -ID oj_attr_hash_get(const char *key, size_t len, ID **slotp) { +VALUE +oj_str_hash_get(const char *key, size_t len, VALUE **slotp) { + return hash_get(&str_hash, key, len, slotp, Qnil); +} + +VALUE +oj_sym_hash_get(const char *key, size_t len, VALUE **slotp) { + return hash_get(&sym_hash, key, len, slotp, Qnil); +} + +ID +oj_attr_hash_get(const char *key, size_t len, ID **slotp) { return (ID)hash_get(&intern_hash, key, len, (VALUE **)slotp, 0); } diff --git a/ext/oj/hash.h b/ext/oj/hash.h index 3a68995f..881fcf7d 100644 --- a/ext/oj/hash.h +++ b/ext/oj/hash.h @@ -11,6 +11,8 @@ typedef struct _hash *Hash; extern void oj_hash_init(); extern VALUE oj_class_hash_get(const char *key, size_t len, VALUE **slotp); +extern VALUE oj_str_hash_get(const char *key, size_t len, VALUE **slotp); +extern VALUE oj_sym_hash_get(const char *key, size_t len, VALUE **slotp); extern ID oj_attr_hash_get(const char *key, size_t len, ID **slotp); extern void oj_hash_print(); diff --git a/ext/oj/mimic_json.c b/ext/oj/mimic_json.c index 500256cb..caddcbb9 100644 --- a/ext/oj/mimic_json.c +++ b/ext/oj/mimic_json.c @@ -389,9 +389,9 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) { } else { VALUE active_hack[1]; - if (Qundef == state_class) { - oj_define_mimic_json(0, NULL, Qnil); - } + if (Qundef == state_class) { + oj_define_mimic_json(0, NULL, Qnil); + } active_hack[0] = rb_funcall(state_class, oj_new_id, 0); oj_dump_obj_to_json_using_params(*argv, copts, &out, 1, active_hack); } @@ -480,7 +480,7 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) { rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n")); } if (Qundef == state_class) { - oj_define_mimic_json(0, NULL, Qnil); + oj_define_mimic_json(0, NULL, Qnil); } rargs[1] = rb_funcall(state_class, oj_new_id, 1, h); @@ -713,6 +713,8 @@ static struct _options mimic_object_to_json_options = {0, // indent No, // safe false, // sec_prec_set No, // ignore_under + Yes, // cache_keys + 3, // cache_str 0, // int_range_min 0, // int_range_max oj_json_class, // create_id diff --git a/ext/oj/oj.c b/ext/oj/oj.c index e2c0d123..22364fdc 100644 --- a/ext/oj/oj.c +++ b/ext/oj/oj.c @@ -106,6 +106,8 @@ static VALUE auto_sym; static VALUE bigdecimal_as_decimal_sym; static VALUE bigdecimal_load_sym; static VALUE bigdecimal_sym; +static VALUE cache_keys_sym; +static VALUE cache_str_sym; static VALUE circular_sym; static VALUE class_cache_sym; static VALUE compat_bigdecimal_sym; @@ -186,6 +188,8 @@ struct _options oj_default_options = { No, // safe false, // sec_prec_set No, // ignore_under + Yes, // cache_keys + 3, // cache_str 0, // int_range_min 0, // int_range_max oj_json_class, // create_id @@ -279,9 +283,11 @@ struct _options oj_default_options = { *used * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted - * - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping - * - *:ignore_under* [Boolean] if true then attributes that start with _ are ignored when dumping in + * - *:ignore* [_nil_|_Array_] either nil or an Array of classes to ignore when dumping + * - *:ignore_under* [_Boolean_] if true then attributes that start with _ are ignored when dumping in *object or custom mode. + * - *:cache_keys* [_Boolean_] if true then hash keys are cached + * - *:cache_str* [_Fixnum_] maximum string value length to cache * - *:integer_range* [_Range_] Dump integers outside range as strings. * - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false (trace is off) * - *:safe* [_true,_|_false_] Safe mimic breaks JSON mimic to be safer, default is false (safe is @@ -389,11 +395,17 @@ static VALUE get_def_opts(VALUE self) { ? Qtrue : ((No == oj_default_options.safe) ? Qfalse : Qnil)); rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec)); + rb_hash_aset(opts, cache_str_sym, INT2FIX(oj_default_options.cache_str)); rb_hash_aset(opts, ignore_under_sym, (Yes == oj_default_options.ignore_under) ? Qtrue : ((No == oj_default_options.ignore_under) ? Qfalse : Qnil)); + rb_hash_aset(opts, + cache_keys_sym, + (Yes == oj_default_options.cache_keys) + ? Qtrue + : ((No == oj_default_options.cache_keys) ? Qfalse : Qnil)); switch (oj_default_options.mode) { case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break; case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break; @@ -557,6 +569,8 @@ static VALUE get_def_opts(VALUE self) { * - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping * - *:ignore_under* [_Boolean_] if true then attributes that start with _ are ignored when *dumping in object or custom mode. + * - *:cache_keys* [_Boolean_] if true then hash keys are cached + * - *:cache_str* [_Fixnum_] maximum string vsalue length to cache * - *:integer_range* [_Range_] Dump integers outside range as strings. * - *:trace* [_Boolean_] turn trace on or off. * - *:safe* [_Boolean_] turn safe mimic on or off. @@ -589,6 +603,7 @@ void oj_parse_options(VALUE ropts, Options copts) { {oj_safe_sym, &copts->safe}, {ignore_under_sym, &copts->ignore_under}, {oj_create_additions_sym, &copts->create_ok}, + {cache_keys_sym, &copts->cache_keys}, {Qnil, 0}}; YesNoOpt o; volatile VALUE v; @@ -647,6 +662,28 @@ void oj_parse_options(VALUE ropts, Options copts) { copts->float_prec = n; } } + if (Qnil != (v = rb_hash_lookup(ropts, cache_str_sym))) { + int n; + +#ifdef RUBY_INTEGER_UNIFICATION + if (rb_cInteger != rb_obj_class(v)) { + rb_raise(rb_eArgError, ":cache_str must be a Integer."); + } +#else + if (T_FIXNUM != rb_type(v)) { + rb_raise(rb_eArgError, ":cache_str must be a Fixnum."); + } +#endif + n = FIX2INT(v); + if (0 >= n) { + copts->cache_str = 0; + } else { + if (32 < n) { + n = 32; + } + copts->cache_str = (char)n; + } + } if (Qnil != (v = rb_hash_lookup(ropts, sec_prec_sym))) { int n; @@ -1816,6 +1853,10 @@ void Init_oj() { rb_gc_register_address(&bigdecimal_load_sym); bigdecimal_sym = ID2SYM(rb_intern("bigdecimal")); rb_gc_register_address(&bigdecimal_sym); + cache_keys_sym = ID2SYM(rb_intern("cache_keys")); + rb_gc_register_address(&cache_keys_sym); + cache_str_sym = ID2SYM(rb_intern("cache_str")); + rb_gc_register_address(&cache_str_sym); circular_sym = ID2SYM(rb_intern("circular")); rb_gc_register_address(&circular_sym); class_cache_sym = ID2SYM(rb_intern("class_cache")); diff --git a/ext/oj/oj.h b/ext/oj/oj.h index de14eaeb..399c0cdc 100644 --- a/ext/oj/oj.h +++ b/ext/oj/oj.h @@ -143,6 +143,8 @@ typedef struct _options { char safe; // YesNo char sec_prec_set; // boolean (0 or 1) char ignore_under; // YesNo - ignore attrs starting with _ if true in object and custom modes + char cache_keys; // YexNo + char cache_str; // string short than or equal to this are cache int64_t int_range_min; // dump numbers below as string int64_t int_range_max; // dump numbers above as string const char * create_id; // 0 or string diff --git a/ext/oj/strict.c b/ext/oj/strict.c index 2706e7cd..b5b74433 100644 --- a/ext/oj/strict.c +++ b/ext/oj/strict.c @@ -8,6 +8,7 @@ #include "encode.h" #include "err.h" +#include "hash.h" #include "oj.h" #include "parse.h" #include "trace.h" @@ -36,9 +37,21 @@ static void add_value(ParseInfo pi, VALUE val) { } static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = Qnil; - rstr = oj_encode(rstr); + if (len <= (size_t)pi->options.cache_str) { + VALUE *slot; + + if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) { + rstr = rb_str_new(str, len); + rstr = oj_encode(rstr); + *slot = rstr; + rb_gc_register_address(slot); + } + } else { + rstr = rb_str_new(str, len); + rstr = oj_encode(rstr); + } pi->stack.head->val = rstr; if (Yes == pi->options.trace) { oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr); @@ -68,20 +81,58 @@ static VALUE start_hash(ParseInfo pi) { static VALUE calc_hash_key(ParseInfo pi, Val parent) { volatile VALUE rkey = parent->key_val; - if (Qundef == rkey) { + if (Qundef != rkey) { + rkey = oj_encode(rkey); + if (Yes == pi->options.sym_key) { + rkey = rb_str_intern(rkey); + } + return rkey; + } + if (Yes != pi->options.cache_keys) { rkey = rb_str_new(parent->key, parent->klen); + rkey = oj_encode(rkey); + if (Yes == pi->options.sym_key) { + rkey = rb_str_intern(rkey); + } + return rkey; } - rkey = oj_encode(rkey); + VALUE *slot; + if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); + if (Qnil == (rkey = oj_sym_hash_get(parent->key, parent->klen, &slot))) { + rkey = rb_str_new(parent->key, parent->klen); + rkey = oj_encode(rkey); + rkey = rb_str_intern(rkey); + *slot = rkey; + rb_gc_register_address(slot); + } + } else { + if (Qnil == (rkey = oj_str_hash_get(parent->key, parent->klen, &slot))) { + rkey = rb_str_new(parent->key, parent->klen); + rkey = oj_encode(rkey); + *slot = rkey; + rb_gc_register_address(slot); + } } return rkey; } static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = Qnil; - rstr = oj_encode(rstr); + if (len <= (size_t)pi->options.cache_str) { + VALUE *slot; + + if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) { + rstr = rb_str_new(str, len); + rstr = oj_encode(rstr); + *slot = rstr; + rb_gc_register_address(slot); + } + } else { + rstr = rb_str_new(str, len); + rstr = oj_encode(rstr); + } rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rstr); if (Yes == pi->options.trace) { oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr); @@ -116,9 +167,21 @@ static VALUE start_array(ParseInfo pi) { } static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = Qnil; - rstr = oj_encode(rstr); + if (len <= (size_t)pi->options.cache_str) { + VALUE *slot; + + if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) { + rstr = rb_str_new(str, len); + rstr = oj_encode(rstr); + *slot = rstr; + rb_gc_register_address(slot); + } + } else { + rstr = rb_str_new(str, len); + rstr = oj_encode(rstr); + } rb_ary_push(stack_peek(&pi->stack)->val, rstr); if (Yes == pi->options.trace) { oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr); diff --git a/notes b/notes index e8e609a4..5eb84bec 100644 --- a/notes +++ b/notes @@ -3,6 +3,17 @@ ^c^d hide subtree ^c^s show subtree +- cache keys and strings + + strict + - compat + - object + - custom + - rails + - wab + - null +- cache 0 help? + + Strict Dump Performance JSON::Ext.dump 20000 times in 0.173 seconds or 115493.546 dump/sec. Oj:strict.dump 20000 times in 0.050 seconds or 401475.753 dump/sec. diff --git a/test/perf_strict.rb b/test/perf_strict.rb index ea1777fb..3a9e86cb 100755 --- a/test/perf_strict.rb +++ b/test/perf_strict.rb @@ -15,6 +15,8 @@ $with_bignum = false $with_nums = true $size = 0 +$symbolize = false +$cache_keys = true opts = OptionParser.new opts.on("-v", "verbose") { $verbose = true } @@ -23,6 +25,8 @@ opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i } opts.on("-b", "with bignum") { $with_bignum = true } opts.on("-n", "without numbers") { $with_nums = false } +opts.on("-z", "--symbolize", "symbolize keys") { $symbolize = true } +opts.on("-k", "--no-cache", "turn off key caching") { $cache_keys = false } opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) } files = opts.parse(ARGV) @@ -51,7 +55,7 @@ } end -Oj.default_options = { :indent => $indent, :mode => :strict } +Oj.default_options = { :indent => $indent, :mode => :strict, cache_keys: $cache_keys, cache_str: 5 } if 0 < $size o = $obj @@ -62,9 +66,6 @@ end $json = Oj.dump($obj) -$obj_json = Oj.dump($obj, :mode => :object) -#puts "*** size: #{$obj_json.size}" -#puts "*** #{$obj_json}" $failed = {} # key is same as String used in tests later def capture_error(tag, orig, load_key, dump_key, &blk) @@ -77,8 +78,13 @@ def capture_error(tag, orig, load_key, dump_key, &blk) end # Verify that all packages dump and load correctly and return the same Object as the original. -capture_error('Oj:strict', $obj, 'load', 'dump') { |o| Oj.strict_load(Oj.dump(o, :mode => :strict)) } -capture_error('Yajl', $obj, 'encode', 'parse') { |o| require 'yajl'; Yajl::Parser.parse(Yajl::Encoder.encode(o)) } +capture_error('Oj:strict', $obj, 'load', 'dump') { |o| + Oj.strict_load(Oj.dump(o)) +} +capture_error('Yajl', $obj, 'encode', 'parse') { |o| + require 'yajl' + Yajl::Parser.parse(Yajl::Encoder.encode(o)) +} capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o| require 'json' require 'json/ext' @@ -86,16 +92,11 @@ def capture_error(tag, orig, load_key, dump_key, &blk) JSON.parser = JSON::Ext::Parser JSON.parse(JSON.generate(o)) } -capture_error('JSON::Pure', $obj, 'generate', 'parse') { |o| - require 'json/pure' - JSON.generator = JSON::Pure::Generator - JSON.parser = JSON::Pure::Parser - JSON.parse(JSON.generate(o)) -} + +Oj.default_options = { symbol_keys: $symbolize } if $verbose puts "json:\n#{$json}\n" - puts "object json:\n#{$obj_json}\n" puts "Oj loaded object:\n#{Oj.strict_load($json)}\n" puts "Yajl loaded object:\n#{Yajl::Parser.parse($json)}\n" puts "JSON loaded object:\n#{JSON::Ext::Parser.new($json).parse}\n" @@ -105,15 +106,11 @@ def capture_error(tag, orig, load_key, dump_key, &blk) puts "Strict Parse Performance" perf = Perf.new() unless $failed.has_key?('JSON::Ext') - perf.add('JSON::Ext', 'parse') { JSON.parse($json) } + perf.add('JSON::Ext', 'parse') { JSON.parse($json, symbolize_names: $symbolize) } perf.before('JSON::Ext') { JSON.parser = JSON::Ext::Parser } end -unless $failed.has_key?('JSON::Pure') - perf.add('JSON::Pure', 'parse') { JSON.parse($json) } - perf.before('JSON::Pure') { JSON.parser = JSON::Pure::Parser } -end unless $failed.has_key?('Oj:strict') - perf.add('Oj:strict', 'strict_load') { Oj.strict_load($json) } + perf.add('Oj:strict', 'strict_load') { Oj.strict_load($json, symbol_keys: true) } end perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl') perf.run($iter) @@ -125,12 +122,8 @@ def capture_error(tag, orig, load_key, dump_key, &blk) perf.add('JSON::Ext', 'dump') { JSON.generate($obj) } perf.before('JSON::Ext') { JSON.generator = JSON::Ext::Generator } end -unless $failed.has_key?('JSON::Pure') - perf.add('JSON::Pure', 'generate') { JSON.generate($obj) } - perf.before('JSON::Pure') { JSON.generator = JSON::Pure::Generator } -end unless $failed.has_key?('Oj:strict') - perf.add('Oj:strict', 'dump') { Oj.dump($obj, :mode => :strict) } + perf.add('Oj:strict', 'dump') { Oj.dump($obj) } end perf.add('Yajl', 'encode') { Yajl::Encoder.encode($obj) } unless $failed.has_key?('Yajl') perf.run($iter) diff --git a/test/test_various.rb b/test/test_various.rb index 7c304f89..f4982db7 100755 --- a/test/test_various.rb +++ b/test/test_various.rb @@ -123,6 +123,8 @@ def test_set_options compat_bigdecimal: true, create_id: 'classy', create_additions: true, + cache_keys: false, + cache_str: 5, space: 'z', array_nl: 'a', object_nl: 'o', From a47b389bb2fc5f5e825274ff3d85267c52e481f3 Mon Sep 17 00:00:00 2001 From: Peter Ohler Date: Sun, 4 Jul 2021 10:50:13 -0400 Subject: [PATCH 2/3] WIP --- ext/oj/compat.c | 49 ++++++++-------- ext/oj/custom.c | 17 +----- ext/oj/parse.h | 3 + ext/oj/strict.c | 148 ++++++++++++++++++++++-------------------------- ext/oj/wab.c | 52 ++++++++++------- notes | 12 ++-- 6 files changed, 132 insertions(+), 149 deletions(-) diff --git a/ext/oj/compat.c b/ext/oj/compat.c index 46135107..63929ce6 100644 --- a/ext/oj/compat.c +++ b/ext/oj/compat.c @@ -23,14 +23,26 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c parent->classname = oj_strndup(str, len); parent->clen = len; } else { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str); if (Qundef == rkey) { - rkey = rb_str_new(key, klen); - rstr = oj_encode(rstr); - rkey = oj_encode(rkey); + VALUE *slot; + if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); + if (Qnil == (rkey = oj_sym_hash_get(key, klen, &slot))) { + rkey = rb_str_new(key, klen); + rkey = oj_encode(rkey); + rkey = rb_str_intern(rkey); + *slot = rkey; + rb_gc_register_address(slot); + } + } else { + if (Qnil == (rkey = oj_str_hash_get(key, klen, &slot))) { + rkey = rb_str_new(key, klen); + rkey = oj_encode(rkey); + *slot = rkey; + rb_gc_register_address(slot); + } } } if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) { @@ -93,23 +105,9 @@ static void end_hash(struct _parseInfo *pi) { } } -static VALUE calc_hash_key(ParseInfo pi, Val parent) { - volatile VALUE rkey = parent->key_val; - - if (Qundef == rkey) { - rkey = rb_str_new(parent->key, parent->klen); - } - rkey = oj_encode(rkey); - if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); - } - return rkey; -} - static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str); - rstr = oj_encode(rstr); if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) { VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); @@ -142,10 +140,10 @@ static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) { rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, - calc_hash_key(pi, parent), + oj_calc_hash_key(pi, parent), rval); } else { - rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval); + rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rval); } if (Yes == pi->options.trace) { oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval); @@ -161,10 +159,10 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) { rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, - calc_hash_key(pi, parent), + oj_calc_hash_key(pi, parent), value); } else { - rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value); + rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value); } if (Yes == pi->options.trace) { oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); @@ -199,9 +197,8 @@ static void array_append_num(ParseInfo pi, NumInfo ni) { } static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str); - rstr = oj_encode(rstr); if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) { VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); diff --git a/ext/oj/custom.c b/ext/oj/custom.c index df75e562..f63fe37c 100644 --- a/ext/oj/custom.c +++ b/ext/oj/custom.c @@ -1010,19 +1010,6 @@ static void end_hash(struct _parseInfo *pi) { } } -static VALUE calc_hash_key(ParseInfo pi, Val parent) { - volatile VALUE rkey = parent->key_val; - - if (Qundef == rkey) { - rkey = rb_str_new(parent->key, parent->klen); - } - rkey = oj_encode(rkey); - if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); - } - return rkey; -} - static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) { Val parent = stack_peek(&pi->stack); volatile VALUE rval = oj_num_as_value(ni); @@ -1067,7 +1054,7 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) { } rval = parent->val; } else { - rb_hash_aset(parent->val, calc_hash_key(pi, kval), rval); + rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), rval); } break; default: break; @@ -1082,7 +1069,7 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) { switch (rb_type(parent->val)) { case T_OBJECT: oj_set_obj_ivar(parent, kval, value); break; - case T_HASH: rb_hash_aset(parent->val, calc_hash_key(pi, kval), value); break; + case T_HASH: rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), value); break; default: break; } if (Yes == pi->options.trace) { diff --git a/ext/oj/parse.h b/ext/oj/parse.h index 5b76498b..f1baacbb 100644 --- a/ext/oj/parse.h +++ b/ext/oj/parse.h @@ -90,6 +90,9 @@ extern void oj_set_wab_callbacks(ParseInfo pi); extern void oj_sparse2(ParseInfo pi); extern VALUE oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd); +extern VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str); +extern VALUE oj_calc_hash_key(ParseInfo pi, Val parent); + static inline void parse_info_init(ParseInfo pi) { memset(pi, 0, sizeof(struct _parseInfo)); } diff --git a/ext/oj/strict.c b/ext/oj/strict.c index b5b74433..5b415634 100644 --- a/ext/oj/strict.c +++ b/ext/oj/strict.c @@ -13,33 +13,10 @@ #include "parse.h" #include "trace.h" -static void hash_end(ParseInfo pi) { - if (Yes == pi->options.trace) { - oj_trace_parse_hash_end(pi, __FILE__, __LINE__); - } -} - -static void array_end(ParseInfo pi) { - if (Yes == pi->options.trace) { - oj_trace_parse_array_end(pi, __FILE__, __LINE__); - } -} - -static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) { - return Qundef; -} - -static void add_value(ParseInfo pi, VALUE val) { - if (Yes == pi->options.trace) { - oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val); - } - pi->stack.head->val = val; -} - -static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { +VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) { volatile VALUE rstr = Qnil; - if (len <= (size_t)pi->options.cache_str) { + if (len <= cache_str) { VALUE *slot; if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) { @@ -47,38 +24,15 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig rstr = oj_encode(rstr); *slot = rstr; rb_gc_register_address(slot); - } + } } else { rstr = rb_str_new(str, len); rstr = oj_encode(rstr); } - pi->stack.head->val = rstr; - if (Yes == pi->options.trace) { - oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr); - } + return rstr; } -static void add_num(ParseInfo pi, NumInfo ni) { - if (ni->infinity || ni->nan) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); - } - pi->stack.head->val = oj_num_as_value(ni); - if (Yes == pi->options.trace) { - oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val); - } -} - -static VALUE start_hash(ParseInfo pi) { - if (Qnil != pi->options.hash_class) { - return rb_class_new_instance(0, NULL, pi->options.hash_class); - } - if (Yes == pi->options.trace) { - oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__); - } - return rb_hash_new(); -} - -static VALUE calc_hash_key(ParseInfo pi, Val parent) { +VALUE oj_calc_hash_key(ParseInfo pi, Val parent) { volatile VALUE rkey = parent->key_val; if (Qundef != rkey) { @@ -117,23 +71,64 @@ static VALUE calc_hash_key(ParseInfo pi, Val parent) { return rkey; } -static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = Qnil; +static void hash_end(ParseInfo pi) { + if (Yes == pi->options.trace) { + oj_trace_parse_hash_end(pi, __FILE__, __LINE__); + } +} - if (len <= (size_t)pi->options.cache_str) { - VALUE *slot; +static void array_end(ParseInfo pi) { + if (Yes == pi->options.trace) { + oj_trace_parse_array_end(pi, __FILE__, __LINE__); + } +} - if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) { - rstr = rb_str_new(str, len); - rstr = oj_encode(rstr); - *slot = rstr; - rb_gc_register_address(slot); - } - } else { - rstr = rb_str_new(str, len); - rstr = oj_encode(rstr); +static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) { + return Qundef; +} + +static void add_value(ParseInfo pi, VALUE val) { + if (Yes == pi->options.trace) { + oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val); } - rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rstr); + pi->stack.head->val = val; +} + +static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { + volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str); + + pi->stack.head->val = rstr; + if (Yes == pi->options.trace) { + oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr); + } +} + +static void add_num(ParseInfo pi, NumInfo ni) { + if (ni->infinity || ni->nan) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + } + pi->stack.head->val = oj_num_as_value(ni); + if (Yes == pi->options.trace) { + oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val); + } +} + +static VALUE start_hash(ParseInfo pi) { + if (Qnil != pi->options.hash_class) { + return rb_class_new_instance(0, NULL, pi->options.hash_class); + } + if (Yes == pi->options.trace) { + oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__); + } + return rb_hash_new(); +} + +static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) { + volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str); + + rb_hash_aset(stack_peek(&pi->stack)->val, + oj_calc_hash_key(pi, parent), + rstr); if (Yes == pi->options.trace) { oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr); } @@ -146,14 +141,18 @@ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) { oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); } v = oj_num_as_value(ni); - rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), v); + rb_hash_aset(stack_peek(&pi->stack)->val, + oj_calc_hash_key(pi, parent), + v); if (Yes == pi->options.trace) { oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v); } } static void hash_set_value(ParseInfo pi, Val parent, VALUE value) { - rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value); + rb_hash_aset(stack_peek(&pi->stack)->val, + oj_calc_hash_key(pi, parent), + value); if (Yes == pi->options.trace) { oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); } @@ -167,21 +166,8 @@ static VALUE start_array(ParseInfo pi) { } static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = Qnil; + volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str); - if (len <= (size_t)pi->options.cache_str) { - VALUE *slot; - - if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) { - rstr = rb_str_new(str, len); - rstr = oj_encode(rstr); - *slot = rstr; - rb_gc_register_address(slot); - } - } else { - rstr = rb_str_new(str, len); - rstr = oj_encode(rstr); - } rb_ary_push(stack_peek(&pi->stack)->val, rstr); if (Yes == pi->options.trace) { oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr); diff --git a/ext/oj/wab.c b/ext/oj/wab.c index 82dd7d98..6096058f 100644 --- a/ext/oj/wab.c +++ b/ext/oj/wab.c @@ -10,6 +10,7 @@ #include "dump.h" #include "encode.h" #include "err.h" +#include "hash.h" #include "oj.h" #include "parse.h" #include "trace.h" @@ -292,6 +293,27 @@ void oj_dump_wab_val(VALUE obj, int depth, Out out) { ///// load functions ///// +static VALUE oj_hash_key(Val parent) { + volatile VALUE rkey = parent->key_val; + + if (Qundef != rkey) { + rkey = oj_encode(rkey); + rkey = rb_str_intern(rkey); + + return rkey; + } + VALUE *slot; + + if (Qnil == (rkey = oj_sym_hash_get(parent->key, parent->klen, &slot))) { + rkey = rb_str_new(parent->key, parent->klen); + rkey = oj_encode(rkey); + rkey = rb_str_intern(rkey); + *slot = rkey; + rb_gc_register_address(slot); + } + return rkey; +} + static void hash_end(ParseInfo pi) { if (Yes == pi->options.trace) { oj_trace_parse_hash_end(pi, __FILE__, __LINE__); @@ -432,7 +454,7 @@ static VALUE protect_uri(VALUE rstr) { return rb_funcall(resolve_uri_class(), oj_parse_id, 1, rstr); } -static VALUE cstr_to_rstr(const char *str, size_t len) { +static VALUE cstr_to_rstr(ParseInfo pi, const char *str, size_t len) { volatile VALUE v = Qnil; if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] && @@ -445,20 +467,20 @@ static VALUE cstr_to_rstr(const char *str, size_t len) { uuid_check(str, (int)len) && Qnil != resolve_wab_uuid_class()) { return rb_funcall(wab_uuid_clas, oj_new_id, 1, rb_str_new(str, len)); } - v = rb_str_new(str, len); if (7 < len && 0 == strncasecmp("http://", str, 7)) { int err = 0; + v = rb_str_new(str, len); volatile VALUE uri = rb_protect(protect_uri, v, &err); if (0 == err) { return uri; } } - return oj_encode(v); + return oj_cstr_to_value(str, len, (size_t)pi->options.cache_str); } static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - pi->stack.head->val = cstr_to_rstr(str, len); + pi->stack.head->val = cstr_to_rstr(pi, str, len); if (Yes == pi->options.trace) { oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val); } @@ -484,22 +506,10 @@ static VALUE start_hash(ParseInfo pi) { return rb_hash_new(); } -static VALUE calc_hash_key(ParseInfo pi, Val parent) { - volatile VALUE rkey = parent->key_val; - - if (Qundef == rkey) { - rkey = rb_str_new(parent->key, parent->klen); - } - rkey = oj_encode(rkey); - rkey = rb_str_intern(rkey); - - return rkey; -} - static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) { - volatile VALUE rval = cstr_to_rstr(str, len); + volatile VALUE rval = cstr_to_rstr(pi, str, len); - rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval); + rb_hash_aset(stack_peek(&pi->stack)->val, oj_hash_key(parent), rval); if (Yes == pi->options.trace) { oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval); } @@ -512,14 +522,14 @@ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) { oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); } rval = oj_num_as_value(ni); - rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval); + rb_hash_aset(stack_peek(&pi->stack)->val, oj_hash_key(parent), rval); if (Yes == pi->options.trace) { oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval); } } static void hash_set_value(ParseInfo pi, Val parent, VALUE value) { - rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value); + rb_hash_aset(stack_peek(&pi->stack)->val, oj_hash_key(parent), value); if (Yes == pi->options.trace) { oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); } @@ -533,7 +543,7 @@ static VALUE start_array(ParseInfo pi) { } static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rval = cstr_to_rstr(str, len); + volatile VALUE rval = cstr_to_rstr(pi, str, len); rb_ary_push(stack_peek(&pi->stack)->val, rval); if (Yes == pi->options.trace) { diff --git a/notes b/notes index 5eb84bec..3d784266 100644 --- a/notes +++ b/notes @@ -4,14 +4,14 @@ ^c^s show subtree - cache keys and strings - + strict - - compat + + strict and null + + compat and rails - object - custom - - rails - - wab - - null -- cache 0 help? + + wab + - scp +- perf_scp + - add note on each to clarify results Strict Dump Performance From 4214cfa8e326386784767e30307c5ea7d2406743 Mon Sep 17 00:00:00 2001 From: Peter Ohler Date: Mon, 5 Jul 2021 20:55:00 -0400 Subject: [PATCH 3/3] Ready for release --- CHANGELOG.md | 4 ++++ ext/oj/custom.c | 1 + ext/oj/object.c | 30 +++++++++++++++++++++++++++++- ext/oj/scp.c | 20 ++++---------------- ext/oj/strict.c | 4 ---- lib/oj/version.rb | 2 +- notes | 34 +++++++--------------------------- test/perf.rb | 2 +- test/perf_scp.rb | 21 +++++++++++---------- test/perf_strict.rb | 3 ++- 10 files changed, 60 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4609b848..3b967015 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 3.12.0 - 2021-07-05 + +- Added string and symbol caching options that give Oj about a 20% parse performance boost. + ## 3.11.8 - 2021-07-03 - Fixed or reverted change that set the default mode when optimize_Rails was called. diff --git a/ext/oj/custom.c b/ext/oj/custom.c index f63fe37c..b4c6893d 100644 --- a/ext/oj/custom.c +++ b/ext/oj/custom.c @@ -955,6 +955,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c } } } else { + //volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str); volatile VALUE rstr = rb_str_new(str, len); if (Qundef == rkey) { diff --git a/ext/oj/object.c b/ext/oj/object.c index f9869025..1f8eba99 100644 --- a/ext/oj/object.c +++ b/ext/oj/object.c @@ -30,11 +30,38 @@ inline static long read_long(const char *str, size_t len) { static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) { volatile VALUE rkey; +#if 0 + VALUE *slot; + if (':' == k1) { + if (Qnil == (rkey = oj_sym_hash_get(kval->key + 1, kval->klen - 1, &slot))) { + rkey = rb_str_new(kval->key + 1, kval->klen - 1); + rkey = oj_encode(rkey); + rkey = rb_str_intern(rkey); + *slot = rkey; + rb_gc_register_address(slot); + } + } else if (Yes == pi->options.sym_key) { + if (Qnil == (rkey = oj_sym_hash_get(kval->key, kval->klen, &slot))) { + rkey = rb_str_new(kval->key, kval->klen); + rkey = oj_encode(rkey); + rkey = rb_str_intern(rkey); + *slot = rkey; + rb_gc_register_address(slot); + } + } else { + if (Qnil == (rkey = oj_str_hash_get(kval->key, kval->klen, &slot))) { + rkey = rb_str_new(kval->key, kval->klen); + rkey = oj_encode(rkey); + *slot = rkey; + rb_gc_register_address(slot); + } + } +#else if (':' == k1) { rkey = rb_str_new(kval->key + 1, kval->klen - 1); rkey = oj_encode(rkey); - rkey = rb_funcall(rkey, oj_to_sym_id, 0); + rkey = rb_str_intern(rkey); } else { rkey = rb_str_new(kval->key, kval->klen); rkey = oj_encode(rkey); @@ -42,6 +69,7 @@ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) { rkey = rb_str_intern(rkey); } } +#endif return rkey; } diff --git a/ext/oj/scp.c b/ext/oj/scp.c index cd9dc27c..c068d99e 100644 --- a/ext/oj/scp.c +++ b/ext/oj/scp.c @@ -9,6 +9,7 @@ #include #include "encode.h" +#include "hash.h" #include "oj.h" #include "parse.h" @@ -82,19 +83,6 @@ static void end_array(ParseInfo pi) { rb_funcall(pi->handler, oj_array_end_id, 0); } -static VALUE calc_hash_key(ParseInfo pi, Val kval) { - volatile VALUE rkey = kval->key_val; - - if (Qundef == rkey) { - rkey = rb_str_new(kval->key, kval->klen); - rkey = oj_encode(rkey); - if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); - } - } - return rkey; -} - static VALUE hash_key(ParseInfo pi, const char *key, size_t klen) { return rb_funcall(pi->handler, oj_hash_key_id, 1, rb_str_new(key, klen)); } @@ -107,7 +95,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c oj_hash_set_id, 3, stack_peek(&pi->stack)->val, - calc_hash_key(pi, kval), + oj_calc_hash_key(pi, kval), rstr); } @@ -116,7 +104,7 @@ static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) { oj_hash_set_id, 3, stack_peek(&pi->stack)->val, - calc_hash_key(pi, kval), + oj_calc_hash_key(pi, kval), oj_num_as_value(ni)); } @@ -125,7 +113,7 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) { oj_hash_set_id, 3, stack_peek(&pi->stack)->val, - calc_hash_key(pi, kval), + oj_calc_hash_key(pi, kval), value); } diff --git a/ext/oj/strict.c b/ext/oj/strict.c index 5b415634..9f81cadf 100644 --- a/ext/oj/strict.c +++ b/ext/oj/strict.c @@ -36,10 +36,6 @@ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) { volatile VALUE rkey = parent->key_val; if (Qundef != rkey) { - rkey = oj_encode(rkey); - if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); - } return rkey; } if (Yes != pi->options.cache_keys) { diff --git a/lib/oj/version.rb b/lib/oj/version.rb index 2a617be8..a0dcaef0 100644 --- a/lib/oj/version.rb +++ b/lib/oj/version.rb @@ -1,5 +1,5 @@ module Oj # Current version of the module. - VERSION = '3.11.8' + VERSION = '3.12.0' end diff --git a/notes b/notes index 3d784266..8bbf0413 100644 --- a/notes +++ b/notes @@ -3,33 +3,13 @@ ^c^d hide subtree ^c^s show subtree -- cache keys and strings - + strict and null - + compat and rails - - object - - custom - + wab - - scp -- perf_scp - - add note on each to clarify results - - -Strict Dump Performance -JSON::Ext.dump 20000 times in 0.173 seconds or 115493.546 dump/sec. -Oj:strict.dump 20000 times in 0.050 seconds or 401475.753 dump/sec. - -Summary: - System time (secs) rate (ops/sec) - --------- ----------- -------------- - Oj:strict 0.050 401475.753 - JSON::Ext 0.173 115493.546 - -Comparison Matrix -(performance factor, 2.0 means row is twice as fast as column) - Oj:strict JSON::Ext - --------- --------- --------- - Oj:strict 1.00 3.48 - JSON::Ext 0.29 1.00 +- parser re-write + - use ojc as a starting point + - should hash be a stack with indicator for either hash or object? + - detect object if create key is encountered else hash + - optimize callbacks + - consider a 4.0 if API changes would be better + - separate defaults for each mode - big decimal - just in custom mode, maybe in strict? diff --git a/test/perf.rb b/test/perf.rb index 83f3b1fb..45c5c964 100644 --- a/test/perf.rb +++ b/test/perf.rb @@ -17,7 +17,7 @@ def before(title, &blk) end end end - + def run(iter) base = Item.new(nil, nil) { } base.run(iter, 0.0) diff --git a/test/perf_scp.rb b/test/perf_scp.rb index 9169e1bf..16330688 100755 --- a/test/perf_scp.rb +++ b/test/perf_scp.rb @@ -14,16 +14,16 @@ $verbose = false $indent = 0 -$iter = 50000 +$iter = 50_000 $with_bignum = false -$size = 0 +$size = 1 opts = OptionParser.new opts.on("-v", "verbose") { $verbose = true } opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i } opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i } -opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i } -opts.on("-b", "with bignum") { $with_bignum = true } +opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i } +opts.on("-b", "with bignum") { $with_bignum = true } opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) } files = opts.parse(ARGV) @@ -47,7 +47,7 @@ end end -Oj.default_options = { :indent => $indent, :mode => :compat } +Oj.default_options = { :indent => $indent, :mode => :strict, cache_keys: true, cache_str: 5 } $json = Oj.dump($obj) $failed = {} # key is same as String used in tests later @@ -105,7 +105,7 @@ def add_value(value) def hash_set(h, key, value) end - + def array_append(a, value) end @@ -137,10 +137,11 @@ def capture_error(tag, orig, load_key, dump_key, &blk) puts '-' * 80 puts "Parse Performance" perf = Perf.new() -perf.add('Oj::Saj', 'all') { Oj.saj_parse(saj_handler, $json) } -perf.add('Oj::Saj', 'none') { Oj.saj_parse(no_saj, $json) } -perf.add('Oj::Scp', 'all') { Oj.sc_parse(sc_handler, $json) } -perf.add('Oj::Scp', 'none') { Oj.sc_parse(no_handler, $json) } +perf.add('Oj::Saj.all', 'all') { Oj.saj_parse(saj_handler, $json) } +perf.add('Oj::Saj.none', 'none') { Oj.saj_parse(no_saj, $json) } +perf.add('Oj::Scp.all', 'all') { Oj.sc_parse(sc_handler, $json) } +perf.add('Oj::Scp.none', 'none') { Oj.sc_parse(no_handler, $json) } +perf.add('Oj::load', 'none') { Oj.wab_load($json) } perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl') perf.add('JSON::Ext', 'parse') { JSON::Ext::Parser.new($json).parse } unless $failed.has_key?('JSON::Ext') perf.run($iter) diff --git a/test/perf_strict.rb b/test/perf_strict.rb index 3a9e86cb..06403301 100755 --- a/test/perf_strict.rb +++ b/test/perf_strict.rb @@ -110,7 +110,8 @@ def capture_error(tag, orig, load_key, dump_key, &blk) perf.before('JSON::Ext') { JSON.parser = JSON::Ext::Parser } end unless $failed.has_key?('Oj:strict') - perf.add('Oj:strict', 'strict_load') { Oj.strict_load($json, symbol_keys: true) } + perf.add('Oj:strict', 'strict_load') { Oj.strict_load($json) } + perf.add('Oj:wab', 'wab_load') { Oj.wab_load($json) } end perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl') perf.run($iter)