Skip to content

Commit

Permalink
Optimize Ext::Generator::State#configure
Browse files Browse the repository at this point in the history
If we assume that most of the time the `opts` hash is small
it's faster to go over the provided keys with a `case` than
to test all possible keys one by one.

Before:

```
== Encoding small nested array (121 bytes)
ruby 3.4.0preview2 (2024-10-07 master 32c733f57b) +YJIT +PRISM [arm64-darwin23]
Warming up --------------------------------------
                json   156.832k i/100ms
                  oj   209.769k i/100ms
           rapidjson   162.922k i/100ms
Calculating -------------------------------------
                json      1.599M (± 2.5%) i/s  (625.34 ns/i) -      7.998M in   5.005110s
                  oj      2.137M (± 1.5%) i/s  (467.99 ns/i) -     10.698M in   5.007806s
           rapidjson      1.677M (± 3.5%) i/s  (596.31 ns/i) -      8.472M in   5.059515s

Comparison:
                json:  1599141.2 i/s
                  oj:  2136785.3 i/s - 1.34x  faster
           rapidjson:  1676977.2 i/s - same-ish: difference falls within error

== Encoding small hash (65 bytes)
ruby 3.4.0preview2 (2024-10-07 master 32c733f57b) +YJIT +PRISM [arm64-darwin23]
Warming up --------------------------------------
                json   216.464k i/100ms
                  oj   661.328k i/100ms
           rapidjson   324.434k i/100ms
Calculating -------------------------------------
                json      2.301M (± 1.7%) i/s  (434.57 ns/i) -     11.689M in   5.081278s
                  oj      7.244M (± 1.2%) i/s  (138.05 ns/i) -     36.373M in   5.021985s
           rapidjson      3.323M (± 2.9%) i/s  (300.96 ns/i) -     16.871M in   5.081696s

Comparison:
                json:  2301142.2 i/s
                  oj:  7243770.3 i/s - 3.15x  faster
           rapidjson:  3322673.0 i/s - 1.44x  faster
```

After:

```
== Encoding small nested array (121 bytes)
ruby 3.4.0preview2 (2024-10-07 master 32c733f57b) +YJIT +PRISM [arm64-darwin23]
Warming up --------------------------------------
                json   168.087k i/100ms
                  oj   208.872k i/100ms
           rapidjson   149.909k i/100ms
Calculating -------------------------------------
                json      1.761M (± 1.1%) i/s  (567.90 ns/i) -      8.909M in   5.059794s
                  oj      2.144M (± 0.9%) i/s  (466.37 ns/i) -     10.861M in   5.065903s
           rapidjson      1.692M (± 1.7%) i/s  (591.04 ns/i) -      8.545M in   5.051808s

Comparison:
                json:  1760868.2 i/s
                  oj:  2144205.9 i/s - 1.22x  faster
           rapidjson:  1691941.1 i/s - 1.04x  slower

== Encoding small hash (65 bytes)
ruby 3.4.0preview2 (2024-10-07 master 32c733f57b) +YJIT +PRISM [arm64-darwin23]
Warming up --------------------------------------
                json   242.957k i/100ms
                  oj   675.217k i/100ms
           rapidjson   355.040k i/100ms
Calculating -------------------------------------
                json      2.569M (± 1.5%) i/s  (389.22 ns/i) -     12.877M in   5.013095s
                  oj      7.128M (± 2.3%) i/s  (140.30 ns/i) -     35.787M in   5.023594s
           rapidjson      3.656M (± 3.1%) i/s  (273.50 ns/i) -     18.462M in   5.054558s

Comparison:
                json:  2569217.5 i/s
                  oj:  7127705.6 i/s - 2.77x  faster
           rapidjson:  3656285.0 i/s - 1.42x  faster
```
  • Loading branch information
byroot committed Oct 17, 2024
1 parent 69955a2 commit 5876f4a
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 19 deletions.
3 changes: 1 addition & 2 deletions lib/json/common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -576,13 +576,12 @@ class << self
# Sets or returns the default options for the JSON.dump method.
# Initially:
# opts = JSON.dump_default_options
# opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
# opts # => {:max_nesting=>false, :allow_nan=>true}
attr_accessor :dump_default_options
end
self.dump_default_options = {
:max_nesting => false,
:allow_nan => true,
:script_safe => false,
}

# :call-seq:
Expand Down
44 changes: 27 additions & 17 deletions lib/json/ext/generator/state.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,35 @@ def configure(opts)
end
end

self.indent = opts[:indent] if opts.key?(:indent)
self.space = opts[:space] if opts.key?(:space)
self.space_before = opts[:space_before] if opts.key?(:space_before)
self.array_nl = opts[:array_nl] if opts.key?(:array_nl)
self.object_nl = opts[:object_nl] if opts.key?(:object_nl)
self.max_nesting = opts[:max_nesting] || 0 if opts.key?(:max_nesting)
self.depth = opts[:depth] if opts.key?(:depth)
self.buffer_initial_length = opts[:buffer_initial_length] if opts.key?(:buffer_initial_length)
self.allow_nan = opts[:allow_nan] if opts.key?(:allow_nan)
self.ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)

if opts.key?(:script_safe)
self.script_safe = opts[:script_safe]
elsif opts.key?(:escape_slash)
self.script_safe = opts[:escape_slash]
opts.each do |key, value|
case key
when :indent
self.indent = value
when :space
self.space = value
when :space_before
self.space_before = value
when :array_nl
self.array_nl = value
when :object_nl
self.object_nl = value
when :max_nesting
self.max_nesting = value || 0
when :depth
self.depth = value
when :buffer_initial_length
self.buffer_initial_length = value
when :allow_nan
self.allow_nan = value
when :ascii_only
self.ascii_only = value
when :script_safe, :escape_slash
self.script_safe = value
when :strict
self.strict = value
end
end

self.strict = opts[:strict] if opts[:strict]

self
end

Expand Down

0 comments on commit 5876f4a

Please sign in to comment.