diff --git a/FSharp.Json.Benchmarks/.gitignore b/FSharp.Json.Benchmarks/.gitignore
new file mode 100644
index 0000000..1c2dac6
--- /dev/null
+++ b/FSharp.Json.Benchmarks/.gitignore
@@ -0,0 +1 @@
+BenchmarkDotNet.Artifacts
\ No newline at end of file
diff --git a/FSharp.Json.Benchmarks/FSharp.Json.Benchmarks.fsproj b/FSharp.Json.Benchmarks/FSharp.Json.Benchmarks.fsproj
new file mode 100644
index 0000000..d372552
--- /dev/null
+++ b/FSharp.Json.Benchmarks/FSharp.Json.Benchmarks.fsproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ netcoreapp2.0
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FSharp.Json.Benchmarks/Main.fs b/FSharp.Json.Benchmarks/Main.fs
new file mode 100644
index 0000000..737adf7
--- /dev/null
+++ b/FSharp.Json.Benchmarks/Main.fs
@@ -0,0 +1,11 @@
+module FSharp.Json.Benchmarks.Main
+
+open System.Reflection
+open BenchmarkDotNet.Running
+
+[]
+let main args =
+ let assembly = Assembly.GetExecutingAssembly()
+ let switcher = new BenchmarkSwitcher(assembly)
+ let summaries = switcher.Run args
+ 0
\ No newline at end of file
diff --git a/FSharp.Json.Benchmarks/Serializers.fs b/FSharp.Json.Benchmarks/Serializers.fs
new file mode 100644
index 0000000..fd60049
--- /dev/null
+++ b/FSharp.Json.Benchmarks/Serializers.fs
@@ -0,0 +1,75 @@
+namespace FSharp.Json.Benchmarks
+
+open System.IO
+open System.Threading
+
+open BenchmarkDotNet.Attributes
+open FSharp.Json
+
+type ISerializer =
+ abstract Name : string
+ abstract Serialize : Stream -> 'T -> unit
+ abstract Deserialize : Stream -> 'T
+
+type JsonDotNetSerializer () =
+ let jdn = Newtonsoft.Json.JsonSerializer.Create()
+
+ interface ISerializer with
+ member __.Name = "Json.Net"
+ member __.Serialize (stream : Stream) (x : 'T) =
+ use writer = new StreamWriter(stream)
+ jdn.Serialize(writer, x)
+ writer.Flush()
+
+ member __.Deserialize (stream : Stream) : 'T =
+ use reader = new StreamReader(stream)
+ jdn.Deserialize(reader, typeof<'T>) :?> 'T
+
+type FSharpJsonSerializer() =
+ let serializerConfig : JsonConfig =
+ {
+ unformatted = true
+ serializeNone = SerializeNone.Null
+ deserializeOption = DeserializeOption.AllowOmit
+ jsonFieldNaming = id
+ allowUntyped = true
+ enumValue = EnumMode.Name
+ }
+
+ interface ISerializer with
+ member __.Name = "FSharp.Json"
+ member __.Serialize (stream : Stream) (x : 'T) =
+ let json = FSharp.Json.Json.serializeEx serializerConfig x
+ let bytes = System.Text.Encoding.ASCII.GetBytes json
+ stream.Write(bytes, 0, bytes.Length)
+
+ member __.Deserialize (stream : Stream) : 'T =
+ use sr = new StreamReader(stream)
+ let json = sr.ReadToEnd()
+ FSharp.Json.Json.deserializeEx serializerConfig json
+
+module Serializer =
+
+ let memoryStream =
+ new ThreadLocal<_>(fun () ->
+ { new MemoryStream() with
+ override __.Close() = () })
+
+ let roundTrip (serializer : ISerializer) (value : 'T) =
+ let m = memoryStream.Value
+ m.Position <- 0L
+ serializer.Serialize m value
+ m.Position <- 0L
+ let _ = serializer.Deserialize<'T> m
+ ()
+
+[]
+[]
+type RoundtripBenchmark<'T>(value : 'T) =
+ let nsj = new JsonDotNetSerializer()
+ let jfs = new FSharpJsonSerializer()
+
+ []
+ member __.NewtonsoftJson() = Serializer.roundTrip nsj value
+ []
+ member __.FSharpJson() = Serializer.roundTrip jfs value
\ No newline at end of file
diff --git a/FSharp.Json.Benchmarks/Types.fs b/FSharp.Json.Benchmarks/Types.fs
new file mode 100644
index 0000000..31799a6
--- /dev/null
+++ b/FSharp.Json.Benchmarks/Types.fs
@@ -0,0 +1,177 @@
+namespace FSharp.Json.Benchmarks
+
+open System
+open FsCheck
+
+module Poco =
+ []
+ type T =
+ { A : int ; B : string ; C : bool ; D : byte[] ;
+ F : DateTimeOffset ; G : TimeSpan ; H : Guid }
+
+ let value = { A = 42 ; B = "lorem ipsum" ; C = true ; D = [|1uy .. 20uy|]
+ F = DateTimeOffset(2018,1,1,23,11,12,TimeSpan.Zero) ;
+ G = TimeSpan.FromDays 30.
+ H = Guid.Empty }
+
+ type PocoRoundtrip() =
+ inherit RoundtripBenchmark(value)
+
+module FloatArray =
+ type T = float[]
+
+ let value =
+ [| for i in 1 .. 100 -> float i / float 100.
+ yield Double.Epsilon
+ yield Double.PositiveInfinity
+ yield Double.NaN
+ yield Double.NegativeInfinity |]
+
+ type FloatArrayRoundtrip() =
+ inherit RoundtripBenchmark(value)
+
+module BoxedArray =
+ type T = obj[]
+
+ let value : T = [|box 1; box "foo" ; box true ; box(1,2) ; box (ref 42) |]
+
+ type BoxedArrayRoundtrip() =
+ inherit RoundtripBenchmark(value)
+
+module Array3D =
+ type T = float [,,]
+
+ let value : T = Array3D.init 20 20 20 (fun i j k -> 0.1 * float i + float j + 10. * float k)
+
+ type Array3DRoundtrip() =
+ inherit RoundtripBenchmark(value)
+
+module LargeTuple =
+ type T = string * int * int * int * bool * string * (float * int list) option * int * int * int * string
+ let value : T = ("lorem ipsum dolor", 1, 2, 3, true, "", Some(3.14, [2]), 3, 2, 1, "lorem")
+
+ type LargeTupleRoundtrip() =
+ inherit RoundtripBenchmark(value)
+
+module FSharpList =
+ type T = int list
+ let value : T = [1..1000]
+
+ type FSharpListRoundtrip() =
+ inherit RoundtripBenchmark(value)
+
+module Dictionary =
+ open System.Collections.Generic
+ open Poco
+
+ type T = Dictionary
+
+ let mkDict size =
+ let d = new T()
+ for i = 1 to size do
+ let key = sprintf "key-%d" i
+ let value = {
+ A = i ;
+ B = sprintf "value-%d" i ;
+ C = i % 2 = 0 ;
+ D = [|byte i|]
+ F = DateTimeOffset(2018,1,1,23,11,12,TimeSpan.Zero) ;
+ G = TimeSpan.FromDays 30.
+ H = Guid.Empty
+ }
+
+ d.Add(key, value)
+ d
+
+ let value = mkDict 1000
+
+ type DictionaryRoundtrip() =
+ inherit RoundtripBenchmark(value)
+
+module ExceptionBench =
+
+ let rec mkExn d =
+ if d = 0 then raise (FormatException "kaboom!")
+ else
+ 1 + mkExn(d - 1)
+
+ let exn = try mkExn 20 |> ignore ; failwith "" with :? FormatException as e -> e
+
+ type ExceptionRoundtrip() =
+ inherit RoundtripBenchmark(exn)
+
+module LargeObject =
+ type Foo = { A : int ; B : string ; C : bool }
+ type Bar = A of int * string | B of Foo | C
+ type T = Bar list list option * string list * byte []
+
+ let value : T [] =
+ Arb.from.Generator |> Gen.sampleWithSeed (Rnd 2019UL) 20 20 |> Seq.toArray
+
+ type LargeFSharpValueRoundtrip() =
+ inherit RoundtripBenchmark(value)
+
+
+module ISerializable =
+ open System.Runtime.Serialization
+
+ type T(x : int, y : string, z : bool) =
+ interface ISerializable with
+ member __.GetObjectData(si, _) =
+ si.AddValue("x", x)
+ si.AddValue("y", y)
+ si.AddValue("z", z)
+
+ new (si : SerializationInfo, _ : StreamingContext) =
+ let inline get x = si.GetValue(x, typeof<'T>) :?> 'T
+ new T(get "x", get "y", get "z")
+
+ let instance = new T(42, "lorem ipsum", true)
+
+ type ISerializableRoundtrip() =
+ inherit RoundtripBenchmark(instance)
+
+
+module FSharpBinTree =
+ type Tree = Node | Leaf of int * Tree * Tree
+
+ let rec mkTree d =
+ if d = 0 then Node
+ else
+ let t = mkTree (d-1)
+ Leaf(d, mkTree(d-1), mkTree(d-1))
+
+ let value = mkTree 10
+
+ type FSharpBinaryRoundtrip() =
+ inherit RoundtripBenchmark(value)
+
+module FSharpSet =
+ let value = set [1 .. 40]
+
+ type FSharpSetRoundtrip() =
+ inherit RoundtripBenchmark>(value)
+
+
+module FSharpMap =
+ let value = [1 .. 40] |> Seq.map (fun i -> string i, i) |> Map.ofSeq
+
+ type FSharpMapRountrip() =
+ inherit RoundtripBenchmark