Skip to content

Instantly share code, notes, and snippets.

@haf
Last active November 12, 2022 07:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save haf/0cc60dfb8e89df6b51aef4f86dbacd57 to your computer and use it in GitHub Desktop.
Save haf/0cc60dfb8e89df6b51aef4f86dbacd57 to your computer and use it in GitHub Desktop.
dotnet build -c Release benchmarks/Chiron.Benchmarks/Chiron.Benchmarks.fsproj && \
dotnet benchmarks/Chiron.Benchmarks/bin/Release/netcoreapp2.0/Chiron.Benchmarks.dll --class ParseTest
// * Summary *
BenchmarkDotNet=v0.10.14, OS=macOS High Sierra 10.13.5 (17F77) [Darwin 17.6.0]
Intel Core i7-7920HQ CPU 3.10GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=2.1.200
[Host] : .NET Core 2.0.7 (CoreCLR 4.6.0.0, CoreFX 4.6.26403.03), 64bit RyuJIT
MediumRun : .NET Core 2.0.7 (CoreCLR 4.6.0.0, CoreFX 4.6.26403.03), 64bit RyuJIT
Job=MediumRun LaunchCount=2 TargetCount=15
WarmupCount=10
Method | Name | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
----------- |----------- |---------------:|------------:|--------------:|----------:|----------:|---------:|-----------:|
Chiron_New | error | 3.423 us | 0.0672 us | 0.0963 us | 0.2823 | - | - | 1200 B |
Newtonsoft | error | 1.926 us | 0.1739 us | 0.2380 us | 1.6289 | - | - | 6840 B |
Chiron_New | fparsec | 19.657 us | 0.2533 us | 0.3551 us | 1.4648 | - | - | 6200 B |
Newtonsoft | fparsec | 9.459 us | 0.0957 us | 0.1432 us | 3.2349 | - | - | 13576 B |
Chiron_New | prettyuser | 48.209 us | 0.7862 us | 1.1768 us | 3.9063 | - | - | 16632 B |
Newtonsoft | prettyuser | 20.805 us | 0.1651 us | 0.2259 us | 5.4626 | - | - | 22968 B |
Chiron_New | social | 125,279.691 us | 825.6099 us | 1,210.1683 us | 5812.5000 | 1937.5000 | 625.0000 | 30154333 B |
Newtonsoft | social | NA | NA | NA | N/A | N/A | N/A | N/A |
Chiron_New | user | 45.557 us | 0.4152 us | 0.6085 us | 3.9063 | - | - | 16632 B |
Newtonsoft | user | 20.237 us | 0.2521 us | 0.3695 us | 5.4626 | - | - | 22968 B |
Benchmarks with issues:
ParseTest.Newtonsoft: MediumRun(LaunchCount=2, TargetCount=15, WarmupCount=10) [Name=social]
namespace ChironB.Benchmarks
open Chiron
open BenchmarkDotNet.Attributes
open Newtonsoft.Json
open Newtonsoft.Json.Linq
module Bench =
open System.IO
open System.Text
let resetStream (stream : #Stream) =
stream.Seek(0L, SeekOrigin.Begin) |> ignore
module Chiron =
let inline parse (stream: #Stream): Json =
let reader = new StreamReader(stream)
reader.ReadToEnd()
|> Json.parse
|> JsonResult.getOrThrow
// let inline parseAndDeserialize (stream : #Stream) : 'a =
// let reader = new StreamReader(stream)
// reader.ReadToEnd()
// |> Json.parse
// |> Json.deserialize
module JsonNET =
let serializer = JsonSerializer.CreateDefault()
let inline parse (stream: #Stream): JObject =
let jsonReader = new StreamReader(stream, Encoding.UTF8)
let reader = new JsonTextReader(jsonReader, CloseInput = false)
JObject.Load reader
[<Config(typeof<CoreConfig>)>]
type ParseTest () =
let mutable jsonStream = null
let mutable jsonString = null
[<Setup>]
member this.Setup () =
jsonString <- loadJsonResourceAsString this.Name
jsonStream <- loadJsonResource this.Name
[<Params("error", "fparsec", "user", "prettyuser", "social")>]
member val Name = "<null>" with get, set
[<Benchmark>]
member __.Chiron_New (): Chiron.JsonResult<Chiron.Json> =
Chiron.Parsing.Json.parse jsonString
[<Benchmark>]
member __.Newtonsoft () =
Bench.resetStream jsonStream
Bench.JsonNET.parse jsonStream
[<Config(typeof<CoreConfig>)>]
type FormatTest () =
let mutable jsonN = Chiron.Json.Null
[<Setup>]
member this.Setup () =
jsonN <-
loadJsonResourceAsString this.Name
|> Chiron.Parsing.Json.parse
|> Chiron.JsonResult.getOrThrow
[<Params("error", "fparsec", "user", "prettyuser", "social")>]
member val Name = "<null>" with get, set
[<Benchmark>]
member __.Chiron_New () =
Chiron.Formatting.Json.format jsonN
[<Config(typeof<CoreConfig>)>]
type FormatVariableLengthStrings () =
let mutable simpleJson = Chiron.Json.Null
let mutable escapedJson = Chiron.Json.Null
[<Params(10, 100, 1000, 10000, 100000)>]
member val public strlen = 1 with get, set
[<Setup>]
member x.Setup () =
let simple = String.replicate x.strlen "a"
simpleJson <- Chiron.Json.String simple
let escaped = String.replicate (x.strlen / 10) "\\u0004\\n\\\""
escapedJson <- Chiron.Json.String escaped
[<Benchmark>]
member __.Simple_New () =
Chiron.Formatting.Json.format simpleJson
[<Benchmark>]
member __.Escaped_New () =
Chiron.Formatting.Json.format escapedJson
@ScottHutchinson
Copy link

So, the way I read these results is: Newtonsoft is faster than Chiron, but uses more memory and does more garbage collecting. Right?

@gusty
Copy link

gusty commented Jul 30, 2018

You can get the best of both worlds by using Fleece which supports NewtonSoft as Json encoder/decoder.

Actually Fleece is the original F# project (the original is Haskell's AESON) while Chiron seems to be a bad copy of Fleece, which implements its own parsers (a bad idea).

@wallymathieu
Copy link

Looks like the performance of Newtonsoft is heavily dependant on where it runs. There are multiple compilation flags. For instance some IL-emit code is not done in netcore, while it's done for some versions of net\d+

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment