michalmuskala / jason

A blazing fast JSON parser and generator in pure Elixir.
Other
1.61k stars 169 forks source link

Optimize decode on small payloads #161

Closed sabiwara closed 1 year ago

sabiwara commented 1 year ago

Hi,

I might have found a small optimization for decoding small payloads: by avoiding creating lambdas and just use pattern-matching where needed, we do slightly less work and use slightly less memory. Hopefully this can benefit tight loops with a lot of decoding calls like this example. This has no impact on bigger benches, so I added a new one.

See bench:

Comparison: 
Jason 2        1.24 M
Jason          1.12 M - 1.11x slower +85.08 ns

Memory usage statistics:

Name       Memory usage
Jason 2           528 B
Jason             648 B - 1.23x memory usage +120 B

Will check Encode as well for a similar approach.

michalmuskala commented 1 year ago

Did you measure any impact on larger payloads?

sabiwara commented 1 year ago

Yes it is unchanged as you can see here:

##### With input Pokedex #####
Name              ips        average  deviation         median         99th %
Jason 2        1.57 K      636.63 μs     ±9.40%      642.38 μs      816.08 μs
Jason          1.57 K      638.13 μs     ±7.69%      637.29 μs      809.00 μs

Comparison: 
Jason 2        1.57 K
Jason          1.57 K - 1.00x slower +1.50 μs

Memory usage statistics:

Name       Memory usage
Jason 2       390.09 KB
Jason         390.21 KB - 1.00x memory usage +0.117 KB
michalmuskala commented 1 year ago

I somewhat tracked down the reason for this slowdown to an Erlang optimisation I introduced in OTP 22 that was accidentally removed by the OTP team in OTP 24. This made lambdas as used here much, much slower. OTP team sent a fix already: https://github.com/erlang/otp/pull/6963

I'll think about how to make this as fast as possible.

sabiwara commented 1 year ago

Tested again with the newly released OTP26 rc2 and I could confirm the optimization works again! 🎉

Now this PR change has no effect:

Comparison: 
Jason          1.71 M
Jason 2        1.68 M - 1.02x slower +10.54 ns

Memory usage statistics:

Name       Memory usage
Jason             528 B
Jason 2           528 B - 1.00x memory usage +0 B