Skip to content
New issue

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

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

Already on GitHub? # to your account

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

Open
wants to merge 3 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.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants