Skip to content

Use bit twiddling for JSON Generation#3

Closed
samyron wants to merge 5 commits into
arm-neon-simdfrom
bitmask-based-simd
Closed

Use bit twiddling for JSON Generation#3
samyron wants to merge 5 commits into
arm-neon-simdfrom
bitmask-based-simd

Conversation

@samyron

@samyron samyron commented Jan 27, 2025

Copy link
Copy Markdown
Owner

Changelog

Use bit twiddling hacks to speed up JSON generation.

Benchmarks from M1 Macbook Air

== Encoding small mixed (34 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json   330.131k i/100ms
                  oj   387.021k i/100ms
Calculating -------------------------------------
                json      4.070M (± 4.7%) i/s  (245.73 ns/i) -     20.468M in   5.044536s
                  oj      3.797M (± 6.6%) i/s  (263.37 ns/i) -     18.964M in   5.018992s

Comparison:
                json:  4069584.9 i/s
                  oj:  3796948.2 i/s - same-ish: difference falls within error


== Encoding small nested array (121 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json   192.904k i/100ms
                  oj   162.632k i/100ms
Calculating -------------------------------------
                json      1.943M (± 0.8%) i/s  (514.62 ns/i) -      9.838M in   5.063260s
                  oj      1.635M (± 1.3%) i/s  (611.70 ns/i) -      8.294M in   5.074536s

Comparison:
                json:  1943177.9 i/s
                  oj:  1634790.9 i/s - 1.19x  slower


== Encoding small hash (65 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json   423.806k i/100ms
                  oj   457.303k i/100ms
Calculating -------------------------------------
                json      4.221M (± 1.1%) i/s  (236.93 ns/i) -     21.190M in   5.021280s
                  oj      4.550M (± 0.9%) i/s  (219.76 ns/i) -     22.865M in   5.025227s

Comparison:
                json:  4220595.9 i/s
                  oj:  4550453.2 i/s - 1.08x  faster


== Encoding mixed utf8 (5003001 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json    56.000 i/100ms
                  oj    32.000 i/100ms
Calculating -------------------------------------
                json    608.762 (±13.5%) i/s    (1.64 ms/i) -      3.024k in   5.071862s
                  oj    332.758 (± 5.1%) i/s    (3.01 ms/i) -      1.664k in   5.013562s

Comparison:
                json:      608.8 i/s
                  oj:      332.8 i/s - 1.83x  slower


== Encoding mostly utf8 (5001001 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json    48.000 i/100ms
                  oj    34.000 i/100ms
Calculating -------------------------------------
                json    544.068 (±13.6%) i/s    (1.84 ms/i) -      2.688k in   5.034129s
                  oj    335.560 (± 3.3%) i/s    (2.98 ms/i) -      1.700k in   5.072160s

Comparison:
                json:      544.1 i/s
                  oj:      335.6 i/s - 1.62x  slower


== Encoding integers (8009 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json     7.359k i/100ms
                  oj     6.882k i/100ms
Calculating -------------------------------------
                json     72.620k (± 4.9%) i/s   (13.77 μs/i) -    367.950k in   5.081712s
                  oj     67.927k (± 4.4%) i/s   (14.72 μs/i) -    344.100k in   5.077263s

Comparison:
                json:    72620.0 i/s
                  oj:    67926.9 i/s - same-ish: difference falls within error


== Encoding activitypub.json (52595 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json     1.912k i/100ms
                  oj     1.463k i/100ms
Calculating -------------------------------------
                json     19.541k (± 4.7%) i/s   (51.17 μs/i) -     97.512k in   5.002059s
                  oj     14.352k (± 3.4%) i/s   (69.67 μs/i) -     71.687k in   5.000899s

Comparison:
                json:    19541.4 i/s
                  oj:    14352.5 i/s - 1.36x  slower


== Encoding citm_catalog.json (500298 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json   105.000 i/100ms
                  oj    87.000 i/100ms
Calculating -------------------------------------
                json      1.037k (± 2.8%) i/s  (964.08 μs/i) -      5.250k in   5.065704s
                  oj    870.841 (± 2.0%) i/s    (1.15 ms/i) -      4.437k in   5.097136s

Comparison:
                json:     1037.3 i/s
                  oj:      870.8 i/s - 1.19x  slower


== Encoding twitter.json (466906 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json   197.000 i/100ms
                  oj   177.000 i/100ms
Calculating -------------------------------------
                json      1.997k (± 6.1%) i/s  (500.67 μs/i) -     10.047k in   5.052436s
                  oj      1.794k (± 2.4%) i/s  (557.52 μs/i) -      9.027k in   5.035769s

Comparison:
                json:     1997.3 i/s
                  oj:     1793.6 i/s - 1.11x  slower


== Encoding canada.json (2090234 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json     1.000 i/100ms
                  oj     1.000 i/100ms
Calculating -------------------------------------
                json     10.273 (± 0.0%) i/s   (97.34 ms/i) -     52.000 in   5.062248s
                  oj     10.075 (± 0.0%) i/s   (99.26 ms/i) -     51.000 in   5.063020s

Comparison:
                json:       10.3 i/s
                  oj:       10.1 i/s - 1.02x  slower


== Encoding many #to_json calls (2701 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                json     2.224k i/100ms
                  oj     1.853k i/100ms
Calculating -------------------------------------
                json     22.282k (± 5.1%) i/s   (44.88 μs/i) -    113.424k in   5.105529s
                  oj     18.528k (± 4.0%) i/s   (53.97 μs/i) -     92.650k in   5.009527s

Comparison:
                json:    22282.5 i/s
                  oj:    18528.1 i/s - 1.20x  slower

@samyron samyron changed the title Use bitmasks Use bit twiddling for JSON Generation Jan 27, 2025
@samyron

samyron commented Jan 27, 2025

Copy link
Copy Markdown
Owner Author

Benchmarks on x86-64 Laptop (Intel(R) Core(TM) i7-8850H)

== Encoding small mixed (34 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json   250.322k i/100ms
                  oj   114.353k i/100ms
Calculating -------------------------------------
                json      2.689M (± 8.0%) i/s  (371.93 ns/i) -     13.517M in   5.086037s
                  oj      2.093M (±32.6%) i/s  (477.77 ns/i) -      9.263M in   5.076968s

Comparison:
                json:  2688681.0 i/s
                  oj:  2093070.7 i/s - same-ish: difference falls within error


== Encoding small nested array (121 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json    63.892k i/100ms
                  oj   106.662k i/100ms
Calculating -------------------------------------
                json      1.066M (±34.2%) i/s  (937.78 ns/i) -      4.728M in   5.037282s
                  oj    628.875k (±11.7%) i/s    (1.59 μs/i) -      3.200M in   5.162507s

Comparison:
                json:  1066352.3 i/s
                  oj:   628874.7 i/s - same-ish: difference falls within error


== Encoding small hash (65 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json   134.794k i/100ms
                  oj   141.854k i/100ms
Calculating -------------------------------------
                json      1.295M (± 3.6%) i/s  (772.00 ns/i) -      6.470M in   5.001461s
                  oj      3.130M (± 5.9%) i/s  (319.52 ns/i) -     15.604M in   5.021108s

Comparison:
                json:  1295329.2 i/s
                  oj:  3129736.8 i/s - 2.42x  faster


== Encoding mixed utf8 (5003001 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json    59.000 i/100ms
                  oj    20.000 i/100ms
Calculating -------------------------------------
                json    595.568 (± 4.5%) i/s    (1.68 ms/i) -      3.009k in   5.065709s
                  oj    204.851 (± 2.9%) i/s    (4.88 ms/i) -      1.040k in   5.081109s

Comparison:
                json:      595.6 i/s
                  oj:      204.9 i/s - 2.91x  slower


== Encoding mostly utf8 (5001001 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json    59.000 i/100ms
                  oj    19.000 i/100ms
Calculating -------------------------------------
                json    583.662 (± 4.1%) i/s    (1.71 ms/i) -      2.950k in   5.063518s
                  oj    182.986 (± 4.4%) i/s    (5.46 ms/i) -    931.000 in   5.098474s

Comparison:
                json:      583.7 i/s
                  oj:      183.0 i/s - 3.19x  slower


== Encoding integers (8009 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json     5.819k i/100ms
                  oj     5.564k i/100ms
Calculating -------------------------------------
                json     44.282k (±26.5%) i/s   (22.58 μs/i) -    209.484k in   5.074081s
                  oj     48.491k (±23.0%) i/s   (20.62 μs/i) -    228.124k in   5.006573s

Comparison:
                json:    44281.6 i/s
                  oj:    48491.4 i/s - same-ish: difference falls within error


== Encoding activitypub.json (52595 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json     1.455k i/100ms
                  oj   897.000 i/100ms
Calculating -------------------------------------
                json     15.121k (± 2.5%) i/s   (66.13 μs/i) -     75.660k in   5.007382s
                  oj      8.975k (± 3.5%) i/s  (111.42 μs/i) -     45.747k in   5.103777s

Comparison:
                json:    15120.7 i/s
                  oj:     8974.9 i/s - 1.68x  slower


== Encoding citm_catalog.json (500298 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json    68.000 i/100ms
                  oj    65.000 i/100ms
Calculating -------------------------------------
                json    355.415 (± 2.0%) i/s    (2.81 ms/i) -      1.836k in   5.167653s
                  oj    315.117 (± 1.6%) i/s    (3.17 ms/i) -      1.625k in   5.158269s

Comparison:
                json:      355.4 i/s
                  oj:      315.1 i/s - 1.13x  slower


== Encoding twitter.json (466906 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json    78.000 i/100ms
                  oj   127.000 i/100ms
Calculating -------------------------------------
                json      1.451k (± 1.7%) i/s  (688.94 μs/i) -      7.332k in   5.052732s
                  oj      1.216k (± 0.6%) i/s  (822.59 μs/i) -      6.096k in   5.014682s

Comparison:
                json:     1451.5 i/s
                  oj:     1215.7 i/s - 1.19x  slower


== Encoding canada.json (2090234 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json     1.000 i/100ms
                  oj     1.000 i/100ms
Calculating -------------------------------------
                json      7.895 (± 0.0%) i/s  (126.66 ms/i) -     40.000 in   5.066501s
                  oj      7.995 (± 0.0%) i/s  (125.07 ms/i) -     40.000 in   5.004558s

Comparison:
                json:        7.9 i/s
                  oj:        8.0 i/s - 1.01x  faster


== Encoding many #to_json calls (2701 bytes)
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
                json     1.312k i/100ms
                  oj   885.000 i/100ms
Calculating -------------------------------------
                json     11.831k (±18.7%) i/s   (84.53 μs/i) -     56.416k in   5.021013s
                  oj      7.477k (±28.7%) i/s  (133.75 μs/i) -     35.400k in   5.125064s

Comparison:
                json:    11830.5 i/s
                  oj:     7476.8 i/s - same-ish: difference falls within error

@samyron samyron closed this Apr 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant