Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance optimisations: Using more value-types and structs #68

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Thorium
Copy link
Member

@Thorium Thorium commented Nov 9, 2023

This commit reduces the memory usage and speeds up all the serialization.

I used also the benchmark-branch all the test that did have result for FSharp.Json,
to run test between the current version and this commit, both run with latest FSharp.Core.
Here are the results:

BenchmarkDotNet=v0.11.5, OS=Windows 10.0.22621
13th Gen Intel Core i9-13900H, 1 CPU, 20 logical and 14 physical cores
.NET Core SDK=8.0.100-rc.1.23463.5
  [Host]     : .NET Core 2.0.9 (CoreCLR 4.6.26614.01, CoreFX 4.6.26614.01), 64bit RyuJIT DEBUG
  DefaultJob : .NET Core 2.0.9 (CoreCLR 4.6.26614.01, CoreFX 4.6.26614.01), 64bit RyuJIT
  1. BoxedArrayRoundtrip
Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated Version
Newtonsoft.Json 3.680 us 0.0302 us 0.0282 us 2.2736 0.0076 - 14 KB 13.0.3
FSharp.Json 12.753 us 0.1331 us 0.1180 us 1.9531 0.0153 - 12.12 KB 0.4.1
FSharp.Json 12.187 us 0.1455 us 0.1361 us 1.8311 0.0153 - 11.41 KB This PR
  1. FSharpBinaryRoundtrip
Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated Version
Newtonsoft.Json 21.00 ms 0.3417 ms 0.3196 ms 3156.25 968.75 375.0000 18.47 MB 13.0.3
FSharp.Json 120.64 ms 2.3876 ms 2.7495 ms 6600.00 200.00 - 40.88 MB 0.4.1
FSharp.Json 107.32 ms 1.5377 ms 1.4384 ms 6000.00 200.00 - 37.29 MB This PR
  1. FSharpListRoundtrip
Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated Version
Newtonsoft.Json 111.8 us 1.560 us 1.459 us 15.7471 0.7324 - 97.62 KB 13.0.3
FSharp.Json 1,012.4 us 12.436 us 11.632 us 138.6719 21.4844 - 869.35 KB 0.4.1
FSharp.Json 997.4 us 11.905 us 10.553 us 126.9531 19.5313 - 798.89 KB This PR
  1. LargeTupleRoundtrip
Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated Version
Newtonsoft.Json 7.808 us 0.0958 us 0.0896 us 2.6703 0.0305 - 16.59 KB 13.0.3
FSharp.Json 27.109 us 0.3354 us 0.3137 us 3.3569 0.0305 - 20.82 KB 0.4.1
FSharp.Json 26.810 us 0.5355 us 0.9656 us 3.1433 0.0305 - 19.59 KB This PR

@Thorium
Copy link
Member Author

Thorium commented Nov 17, 2023

The figures are still so bad that people should prefer System.Text.Json and Newtonsoft.Json over this library.

@bartelink
Copy link
Member

Yes, far too many moving parts
If going NSJ (which is a bad idea for new systems as it's a dead end), FsCodec.NewtonsoftJson includes required converters for things like options
(FsCodec.SystemTextJson has shims too, but those are a lot less necessary than they are for NSJ)
Also if you want lots of features and dot mind taking a dep on a larger lib, look at FSharp.SystemTextJson

@Thorium
Copy link
Member Author

Thorium commented Nov 17, 2023

I asked @eiriktsarpalis the best method for custom parsing json with System.Text.Json, he said:

just use Utf8JsonReader under wraps. That way make sure it's compliant and also take advantage of all the vectorization code it's using under the hood.

So I tried a bit: https://gist.github.com/Thorium/09a67ce08adee4fcc02ec7f0048e6962
That could work here as well.

@bartelink
Copy link
Member

I should mention though - while GC and perf for STJ is in another league, ultimately the perf of JSON serialization is not make or break for 99% of systems. i.e. my motivations for mentioning other libs is not primarily based on perf, more:

  • for new systems, you get to make a choice. For older systems, deciding to shift serializers should not be taken lightly
  • depending on less semi-maintained code with bespoke behaviors (vs FSharp.Json and FSharp.SystemTextJson)
  • STJ and NSJ by having more traffic/being more mainstream is easier to search up answers for on SO and troubleshoot
  • NSJ obviously has broad usage and probably most features, but is also extremely a clear dead end - just scan the issue tracker

@Thorium
Copy link
Member Author

Thorium commented Nov 18, 2023

Fair point, however often JSON is used in data communications which often means there is either active user looking progress-bar, or there is a huge batch process going on, so speed is somewhat a property.

Beside the options you mentioned there is FSharp.Data.JsonProvider which is extremely convenient to use, having its own parser.

Right now I feel that F# eco-system has had this problem of everyone copy&pasting their own serialization implementations (and AI-tools will make this even easier in the future). And because everything is OSS, people also referencing single serialization-implementation files directly (e.g. paket files). That's why fixing old code is important even in old less-maintained sources.

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.

None yet

2 participants