├── .gitignore ├── Benchmark ├── .gitignore ├── 0-compile-model.bat ├── 1-deploy-benchmark-jar.bat ├── App.config ├── FlatBuf │ ├── SmallObjects.Complex.fbs │ ├── SmallObjects.Message.fbs │ └── SmallObjects.Post.fbs ├── JsonBenchmark.csproj ├── JsonBenchmark.sln ├── LargeObjects.dsl ├── LibrarySetup.cs ├── Models.Large.cs ├── Models.Small.cs ├── Models.Standard.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── SmallObjects.dsl ├── StandardObjects.dsl ├── bond │ ├── BondConverters.cs │ ├── SmallObjects.bond │ ├── SmallObjects_types.cs │ ├── StandardObjects.bond │ └── StandardObjects_types.cs ├── lib │ ├── ServerModel.dll │ ├── generated-model.jar │ └── hr │ │ └── ngs │ │ └── benchmark │ │ └── generated-model │ │ ├── 1.6 │ │ ├── generated-model-1.6.jar │ │ ├── generated-model-1.6.jar.md5 │ │ ├── generated-model-1.6.jar.sha1 │ │ ├── generated-model-1.6.pom │ │ ├── generated-model-1.6.pom.md5 │ │ └── generated-model-1.6.pom.sha1 │ │ ├── maven-metadata.xml │ │ ├── maven-metadata.xml.md5 │ │ └── maven-metadata.xml.sha1 ├── pom.xml └── src │ └── main │ └── java │ ├── FlatBuf │ └── SmallObjects │ │ ├── Complex.java │ │ ├── Message.java │ │ └── Post.java │ ├── com │ └── google │ │ └── flatbuffers │ │ ├── Constants.java │ │ ├── FlatBufferBuilder.java │ │ ├── Struct.java │ │ └── Table.java │ └── hr │ └── ngs │ └── benchmark │ ├── Main.java │ ├── Serializer.java │ └── serializers │ ├── AlibabaSerializer.java │ ├── BoonSerializer.java │ ├── DslJsonSerializer.java │ ├── FlatBufSerializer.java │ ├── FlexJsonSerializer.java │ ├── FstSerializer.java │ ├── GensonSerializer.java │ ├── GsonSerializer.java │ ├── JacksonSerializer.java │ └── KryoSerializer.java ├── GatherResults ├── GatherResults.csproj ├── GatherResults.sln ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── template.xlsx ├── LICENSE ├── README.md ├── app ├── Bond.Attributes.dll ├── Bond.IO.dll ├── Bond.JSON.dll ├── Bond.dll ├── GatherResults.exe ├── Jil.dll ├── JsonBenchmark.exe ├── JsonBenchmark.exe.config ├── NGS.Templater.dll ├── NetJSON.dll ├── Newtonsoft.Json.dll ├── Revenj.Common.dll ├── Revenj.DomainPatterns.Interface.dll ├── Revenj.DomainPatterns.dll ├── Revenj.Extensibility.Interface.dll ├── Revenj.Serialization.Interface.dll ├── Revenj.Serialization.dll ├── Revenj.Utility.dll ├── ServerModel.dll ├── ServiceStack.Text.dll ├── Sigil.dll ├── fastJSON.dll ├── json-benchmark.jar ├── protobuf-net.dll └── template.xlsx └── results ├── large-1000-2015.png ├── large-1000-2016.png ├── large-500-2016-7.png ├── net-vs-mono-2015.png ├── net-vs-mono-2016.png ├── result-dotnet-vs-mono-2015.xlsx ├── result-dotnet-vs-mono-2016.xlsx ├── results-linux-2015.xlsx ├── results-linux-2016.xlsx ├── results-windows-2015.xlsx ├── results-windows-2016-7.xlsx ├── results-windows-2016.xlsx ├── small-complex-2016.png ├── small-objects-2015.png ├── small-objects-2016-7.png ├── small-objects-2016.png ├── standard-post-2015.png ├── standard-post-2016-7.png ├── standard-post-2016.png ├── startup-small-2015.png ├── startup-small-2016-7.png └── startup-small-2016.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #ignore thumbnails created by windows 3 | Thumbs.db 4 | #Ignore files build by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.pidb 9 | *.user 10 | *.aps 11 | *.pch 12 | *.vspscc 13 | *.vsp 14 | *.dll 15 | *_i.c 16 | *_p.c 17 | *.ncb 18 | *.suo 19 | *.sln.docstates 20 | *.tlb 21 | *.tlh 22 | *.bak 23 | *.ilk 24 | *.log 25 | [Bb]in 26 | [Dd]ebug*/ 27 | *.lib 28 | *.sbr 29 | obj/ 30 | [Rr]elease*/ 31 | _ReSharper*/ 32 | Dotfuscated/ 33 | [Tt]est[Rr]esult* 34 | 35 | .idea 36 | *.iml 37 | 38 | target 39 | /Benchmark/.vs/JsonBenchmark/v16/Server/sqlite3 40 | -------------------------------------------------------------------------------- /Benchmark/.gitignore: -------------------------------------------------------------------------------- 1 | dependencies 2 | -------------------------------------------------------------------------------- /Benchmark/0-compile-model.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cd "%~dp0" 3 | 4 | java -jar dsl-clc.jar java_pojo=lib\generated-model.jar dsl=. namespace=hr.ngs.benchmark manual-json jackson java-beans download 5 | 6 | call mvn deploy:deploy-file -Durl=file://lib -Dfile=lib/generated-model.jar -DgroupId=hr.ngs.benchmark -DartifactId=generated-model -Dpackaging=jar -Dversion=1.6 -------------------------------------------------------------------------------- /Benchmark/1-deploy-benchmark-jar.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cd "%~dp0" 3 | 4 | call mvn clean compile package 5 | 6 | if exist target\json-benchmark-1.0.0-SNAPSHOT-jar-with-dependencies.jar ( 7 | copy target\json-benchmark-1.0.0-SNAPSHOT-jar-with-dependencies.jar ..\app\json-benchmark.jar 8 | ) 9 | -------------------------------------------------------------------------------- /Benchmark/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Benchmark/FlatBuf/SmallObjects.Complex.fbs: -------------------------------------------------------------------------------- 1 | namespace FlatBuf.SmallObjects; 2 | 3 | table Complex { 4 | x:string;//decimal; 5 | y:float; 6 | z:long; 7 | } 8 | 9 | root_type Complex; -------------------------------------------------------------------------------- /Benchmark/FlatBuf/SmallObjects.Message.fbs: -------------------------------------------------------------------------------- 1 | namespace FlatBuf.SmallObjects; 2 | 3 | table Message { 4 | message:string; 5 | version:int; 6 | } 7 | 8 | root_type Message; -------------------------------------------------------------------------------- /Benchmark/FlatBuf/SmallObjects.Post.fbs: -------------------------------------------------------------------------------- 1 | namespace FlatBuf.SmallObjects; 2 | 3 | table Post { 4 | ID:string;//guid; 5 | title:string; 6 | active:bool; 7 | created:long;//date; 8 | } 9 | 10 | root_type Post; -------------------------------------------------------------------------------- /Benchmark/JsonBenchmark.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {2F9C5E70-99D4-4365-A243-61075B19FB5C} 9 | Exe 10 | Properties 11 | JsonBenchmark 12 | JsonBenchmark 13 | v4.7.2 14 | 15 | 16 | 512 17 | 18 | 19 | x86 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | x86 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | AnyCPU 39 | true 40 | full 41 | false 42 | bin\Debug\ 43 | DEBUG;TRACE 44 | prompt 45 | 4 46 | 47 | 48 | AnyCPU 49 | true 50 | bin\Release\ 51 | prompt 52 | 4 53 | false 54 | 55 | 56 | 57 | ..\app\Bond.dll 58 | 59 | 60 | ..\app\Bond.Attributes.dll 61 | 62 | 63 | ..\app\Bond.IO.dll 64 | 65 | 66 | ..\app\Bond.JSON.dll 67 | 68 | 69 | ..\app\fastJSON.dll 70 | 71 | 72 | ..\app\Jil.dll 73 | 74 | 75 | ..\app\NetJSON.dll 76 | 77 | 78 | ..\app\Newtonsoft.Json.dll 79 | 80 | 81 | ..\app\protobuf-net.dll 82 | 83 | 84 | ..\app\Revenj.DomainPatterns.dll 85 | 86 | 87 | ..\app\Revenj.DomainPatterns.Interface.dll 88 | 89 | 90 | ..\app\Revenj.Extensibility.Interface.dll 91 | 92 | 93 | ..\app\Revenj.Utility.dll 94 | 95 | 96 | ..\app\Revenj.Serialization.dll 97 | 98 | 99 | ..\app\Revenj.Serialization.Interface.dll 100 | 101 | 102 | lib\ServerModel.dll 103 | 104 | 105 | ..\app\ServiceStack.Text.dll 106 | 107 | 108 | ..\app\Sigil.dll 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | Designer 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 154 | -------------------------------------------------------------------------------- /Benchmark/JsonBenchmark.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonBenchmark", "JsonBenchmark.csproj", "{2F9C5E70-99D4-4365-A243-61075B19FB5C}" 7 | EndProject 8 | Global 9 | GlobalSection(DslPlatformSolutionProperties) = preSolution 10 | Postgres.ConnectionString = server=localhost 11 | Php.Name = Php 12 | Php.Target = Php 13 | Postgres.Compile = True 14 | Postgres.Name = ServerModel 15 | Postgres.WithManualJson = True 16 | Postgres.UseUtc = True 17 | Postgres.MinimalSerialization = True 18 | EndGlobalSection 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Debug|x86 = Debug|x86 22 | Release|Any CPU = Release|Any CPU 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {2F9C5E70-99D4-4365-A243-61075B19FB5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {2F9C5E70-99D4-4365-A243-61075B19FB5C}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {2F9C5E70-99D4-4365-A243-61075B19FB5C}.Debug|x86.ActiveCfg = Debug|x86 29 | {2F9C5E70-99D4-4365-A243-61075B19FB5C}.Debug|x86.Build.0 = Debug|x86 30 | {2F9C5E70-99D4-4365-A243-61075B19FB5C}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {2F9C5E70-99D4-4365-A243-61075B19FB5C}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {2F9C5E70-99D4-4365-A243-61075B19FB5C}.Release|x86.ActiveCfg = Release|x86 33 | {2F9C5E70-99D4-4365-A243-61075B19FB5C}.Release|x86.Build.0 = Release|x86 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /Benchmark/LargeObjects.dsl: -------------------------------------------------------------------------------- 1 | module LargeObjects { 2 | value Book { 3 | int ID; 4 | string title; 5 | int authorId; 6 | linked list pages; 7 | date? published; 8 | binary? cover; 9 | Set changes; 10 | Map metadata; 11 | Array genres; 12 | } 13 | enum Genre { 14 | Action; 15 | Romance; 16 | Comedy; 17 | SciFi; 18 | } 19 | value Page { 20 | string text; 21 | List notes; 22 | guid identity; 23 | } 24 | value Footnote { 25 | has mixin Note; 26 | timestamp createadAt { 27 | //otherwise we will get current date 28 | default c# 'System.DateTime.MinValue'; 29 | default Java 'com.dslplatform.json.JavaTimeConverter.MIN_DATE_TIME_UTC'; 30 | } 31 | long index; 32 | } 33 | value Headnote { 34 | has mixin Note; 35 | timestamp? modifiedAt; 36 | } 37 | mixin Note { 38 | string note; 39 | string(100)? writtenBy; 40 | } 41 | } -------------------------------------------------------------------------------- /Benchmark/LibrarySetup.cs: -------------------------------------------------------------------------------- 1 | using Bond.IO.Unsafe; 2 | using Bond.Protocols; 3 | using ProtoBuf.Meta; 4 | using Revenj.Serialization; 5 | using Revenj.Utility; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.IO; 9 | using System.Runtime.Serialization; 10 | using System.Runtime.Serialization.Formatters; 11 | 12 | namespace JsonBenchmark 13 | { 14 | internal static class LibrarySetup 15 | { 16 | class RevenjBinder : SerializationBinder 17 | { 18 | public override Type BindToType(string assemblyName, string typeName) 19 | { 20 | return null; 21 | } 22 | 23 | public override void BindToName(Type serializedType, out string assemblyName, out string typeName) 24 | { 25 | assemblyName = null; 26 | typeName = serializedType.FullName; 27 | } 28 | } 29 | 30 | public static void SetupRevenj( 31 | out Action serialize, 32 | out Func deserialize, 33 | bool minimal) 34 | { 35 | JsonSerialization serialization = new JsonSerialization(new RevenjBinder()); 36 | serialize = (obj, stream) => serialization.Serialize(obj, stream, minimal); 37 | deserialize = (stream, type) => serialization.Deserialize(stream, type, default(StreamingContext)); 38 | } 39 | 40 | public static void SetupNewtonsoftJson( 41 | out Action serialize, 42 | out Func deserialize) 43 | { 44 | var serializer = new Newtonsoft.Json.JsonSerializer(); 45 | serializer.TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple; 46 | serializer.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto; 47 | serialize = (obj, stream) => 48 | { 49 | var sw = new Newtonsoft.Json.JsonTextWriter(stream.GetWriter()); 50 | serializer.Serialize(sw, obj); 51 | sw.Flush(); 52 | }; 53 | deserialize = (stream, type) => serializer.Deserialize(new Newtonsoft.Json.JsonTextReader(stream.GetReader()), type); 54 | } 55 | 56 | public static void SetupUtf8Json(out Action serialize, out Func deserialize) 57 | { 58 | serialize = (obj, stream) => Utf8Json.JsonSerializer.Serialize(stream, obj); 59 | deserialize = (stream, type) => Utf8Json.JsonSerializer.NonGeneric.Deserialize(type, stream); 60 | } 61 | 62 | public static void SetupProtobuf( 63 | out Action serialize, 64 | out Func deserialize) 65 | { 66 | var model = RuntimeTypeModel.Create(); 67 | model.InferTagFromNameDefault = true; 68 | serialize = (obj, stream) => model.Serialize(stream, obj); 69 | deserialize = (stream, type) => model.Deserialize(stream, null, type); 70 | } 71 | 72 | public static void SetupJil( 73 | out Action serialize, 74 | out Func deserialize) 75 | { 76 | serialize = (obj, stream) => 77 | { 78 | var sw = stream.GetWriter(); 79 | Jil.JSON.Serialize(obj, sw, Jil.Options.ISO8601); 80 | sw.Flush(); 81 | }; 82 | deserialize = (stream, type) => Jil.JSON.Deserialize(stream.GetReader(), type, Jil.Options.ISO8601); 83 | } 84 | 85 | public static void SetupBondJson( 86 | out Action serialize, 87 | out Func deserialize) 88 | { 89 | var serializers = new Dictionary>(); 90 | var deserializers = new Dictionary>(); 91 | serialize = (obj, stream) => 92 | { 93 | var jsonWriter = new SimpleJsonWriter(stream); 94 | var type = obj.GetType(); 95 | Bond.Serializer serializer; 96 | if (!serializers.TryGetValue(type, out serializer)) 97 | serializers[type] = serializer = new Bond.Serializer(type); 98 | serializer.Serialize(obj, jsonWriter); 99 | jsonWriter.Flush(); 100 | }; 101 | deserialize = (stream, type) => 102 | { 103 | var reader = new SimpleJsonReader(stream); 104 | Bond.Deserializer deserializer; 105 | if (!deserializers.TryGetValue(type, out deserializer)) 106 | deserializers[type] = deserializer = new Bond.Deserializer(type); 107 | return deserializer.Deserialize(reader); 108 | }; 109 | } 110 | 111 | public static void SetupBondBinary( 112 | out Action serialize, 113 | out Func deserialize) 114 | { 115 | var serializers = new Dictionary>>(); 116 | var deserializers = new Dictionary>>(); 117 | serialize = (obj, stream) => 118 | { 119 | var output = new OutputStream(stream, 512); 120 | var writer = new FastBinaryWriter(output); 121 | Bond.Serializer> serializer; 122 | var type = obj.GetType(); 123 | if (!serializers.TryGetValue(type, out serializer)) 124 | serializers[type] = serializer = new Bond.Serializer>(type); 125 | serializer.Serialize(obj, writer); 126 | output.Flush(); 127 | }; 128 | deserialize = (stream, type) => 129 | { 130 | var input = new InputStream(stream, 512); 131 | var reader = new FastBinaryReader(input); 132 | Bond.Deserializer> deserializer; 133 | if (!deserializers.TryGetValue(type, out deserializer)) 134 | deserializers[type] = deserializer = new Bond.Deserializer>(type); 135 | return deserializer.Deserialize(reader); 136 | }; 137 | } 138 | 139 | public static void SetupFastJson( 140 | out Action serialize, 141 | out Func deserialize) 142 | { 143 | fastJSON.JSON.Parameters.UseExtensions = false; 144 | serialize = (obj, stream) => 145 | { 146 | var sw = stream.GetWriter(); 147 | sw.Write(fastJSON.JSON.ToJSON(obj)); 148 | sw.Flush(); 149 | }; 150 | //TODO: forced to string conversion ;( 151 | deserialize = (stream, type) => fastJSON.JSON.ToObject(stream.GetReader().ReadToEnd(), type); 152 | } 153 | 154 | public static void SetupServiceStack( 155 | out Action serialize, 156 | out Func deserialize) 157 | { 158 | serialize = (obj, stream) => 159 | { 160 | var writer = stream.GetWriter(); 161 | ServiceStack.Text.JsonSerializer.SerializeToWriter(obj, writer); 162 | writer.Flush(); 163 | //let's reuse reader and writer since it's faster than sending stream 164 | //ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream); 165 | }; 166 | deserialize = (stream, type) => 167 | { 168 | var reader = stream.GetReader(); 169 | return ServiceStack.Text.JsonSerializer.DeserializeFromReader(reader, type); 170 | //ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream); 171 | }; 172 | } 173 | 174 | public static void SetupNetJSON( 175 | out Action serialize, 176 | out Func deserialize) 177 | { 178 | var serializers = new Dictionary>(); 179 | var deserializers = new Dictionary>(); 180 | NetJSON.NetJSON.DateFormat = NetJSON.NetJSONDateFormat.ISO; 181 | //TODO: not really nice... but let's avoid to string conversion 182 | serializers[typeof(Models.Small.Message)] = (tw, obj) => NetJSON.NetJSON.Serialize((Models.Small.Message)obj, tw); 183 | serializers[typeof(Models.Small.Complex)] = (tw, obj) => NetJSON.NetJSON.Serialize((Models.Small.Complex)obj, tw); 184 | serializers[typeof(Models.Small.Post)] = (tw, obj) => NetJSON.NetJSON.Serialize((Models.Small.Post)obj, tw); 185 | serializers[typeof(Models.Standard.DeletePost)] = (tw, obj) => NetJSON.NetJSON.Serialize((Models.Standard.DeletePost)obj, tw); 186 | serializers[typeof(Models.Standard.Post)] = (tw, obj) => NetJSON.NetJSON.Serialize((Models.Standard.Post)obj, tw); 187 | serializers[typeof(Models.Large.Book)] = (tw, obj) => NetJSON.NetJSON.Serialize((Models.Large.Book)obj, tw); 188 | deserializers[typeof(Models.Small.Message)] = reader => NetJSON.NetJSON.Deserialize(reader); 189 | deserializers[typeof(Models.Small.Complex)] = reader => NetJSON.NetJSON.Deserialize(reader); 190 | deserializers[typeof(Models.Small.Post)] = reader => NetJSON.NetJSON.Deserialize(reader); 191 | deserializers[typeof(Models.Standard.DeletePost)] = reader => NetJSON.NetJSON.Deserialize(reader); 192 | deserializers[typeof(Models.Standard.Post)] = reader => NetJSON.NetJSON.Deserialize(reader); 193 | deserializers[typeof(Models.Large.Book)] = reader => NetJSON.NetJSON.Deserialize(reader); 194 | serialize = (obj, stream) => 195 | { 196 | var writer = stream.GetWriter(); 197 | serializers[obj.GetType()](writer, obj); 198 | writer.Flush(); 199 | }; 200 | deserialize = (stream, type) => deserializers[type](stream.GetReader()); 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /Benchmark/Models.Large.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.Serialization; 5 | using System.Text; 6 | 7 | namespace JsonBenchmark.Models.Large 8 | { 9 | [DataContract] 10 | public class Book : IEquatable 11 | { 12 | private static DateTime NOW = DateTime.UtcNow; 13 | private static List ILLUSTRATIONS = new List(); 14 | static Book() 15 | { 16 | var rnd = new Random(1); 17 | for (int i = 0; i < 10; i++) 18 | { 19 | var buf = new byte[256 * i * i * i]; 20 | rnd.NextBytes(buf); 21 | ILLUSTRATIONS.Add(buf); 22 | } 23 | } 24 | 25 | public Book() 26 | { 27 | pages = new LinkedList(); 28 | changes = new HashSet(); 29 | metadata = new Dictionary(); 30 | genres = new Genre[0]; 31 | cover = new byte[0];//otherwise buggy ProtoBuf and some other libs 32 | } 33 | [DataMember(Order = 2)] 34 | public int ID { get; set; } 35 | [DataMember(Order = 3)] 36 | public string title { get; set; } 37 | [DataMember(Order = 4)] 38 | public int authorId { get; set; } 39 | [DataMember(Order = 5)] 40 | public LinkedList pages { get; set; } 41 | [DataMember(Order = 6)] 42 | public DateTime? published { get; set; } 43 | [DataMember(Order = 7)] 44 | public byte[] cover { get; set; } 45 | [DataMember(Order = 8)] 46 | public HashSet changes { get; set; } 47 | [DataMember(Order = 9)] 48 | public Dictionary metadata { get; set; } 49 | [DataMember(Order = 10)] 50 | public Genre[] genres { get; set; } 51 | public override int GetHashCode() { return ID; } 52 | public override bool Equals(object obj) { return Equals(obj as Book); } 53 | public bool Equals(Book other) 54 | { 55 | var otherChanges = other != null ? other.changes.ToList() : null; 56 | var thisChanges = changes.ToList(); 57 | if (otherChanges != null) otherChanges.Sort(); 58 | thisChanges.Sort(); 59 | var otherKeys = other != null ? other.metadata.Keys.ToList() : null; 60 | var thisKeys = this.metadata.Keys.ToList(); 61 | if (otherKeys != null) otherKeys.Sort(); 62 | thisKeys.Sort(); 63 | return other != null && other.ID == this.ID && other.title == this.title 64 | && other.authorId == this.authorId 65 | && other.pages != null && Enumerable.SequenceEqual(other.pages, this.pages) 66 | && other.published == this.published 67 | && other.cover != null && Enumerable.SequenceEqual(other.cover, this.cover) 68 | && otherChanges != null && Enumerable.SequenceEqual(otherChanges, thisChanges) 69 | && otherKeys != null && Enumerable.SequenceEqual(otherKeys, thisKeys) 70 | && otherKeys.All(it => other.metadata[it] == this.metadata[it]) 71 | && other.genres != null && Enumerable.SequenceEqual(other.genres, this.genres); 72 | } 73 | public static TB Factory(int i, Func cast) 74 | where TB : new() 75 | where TG : struct 76 | where TP : new() 77 | where TH : new() 78 | where TF : new() 79 | { 80 | dynamic book = new TB(); 81 | book.ID = -i; 82 | book.authorId = i / 100; 83 | book.published = i % 3 == 0 ? null : (DateTime?)NOW.AddMinutes(i).Date; 84 | book.title = "book title " + i; 85 | var genres = new TG[i % 2]; 86 | for (int j = 0; j < i % 2; j++) 87 | genres[j] = cast((i + j) % 4); 88 | book.genres = genres; 89 | for (int j = 0; j < i % 20; j++) 90 | book.changes.Add(NOW.AddMinutes(i).Date); 91 | for (int j = 0; j < i % 50; j++) 92 | book.metadata["key " + i + j] = "value " + i + j; 93 | if (i % 3 == 0 || i % 7 == 0) book.cover = ILLUSTRATIONS[i % ILLUSTRATIONS.Count]; 94 | var sb = new StringBuilder(); 95 | for (int j = 0; j < i % 1000; j++) 96 | { 97 | sb.Append("some text on page " + j); 98 | sb.Append("more text for " + i); 99 | dynamic page = new TP(); 100 | page.text = sb.ToString(); 101 | for (int z = 0; z < i % 100; z++) 102 | { 103 | dynamic note; 104 | if (z % 3 == 0) 105 | { 106 | note = new TH(); 107 | note.modifiedAt = NOW.AddSeconds(i); 108 | note.note = "headnote " + j + " at " + z; 109 | } 110 | else 111 | { 112 | note = new TF(); 113 | note.createadAt = NOW.AddSeconds(i); 114 | note.note = "footnote " + j + " at " + z; 115 | note.index = i; 116 | } 117 | if (z % 3 == 0) 118 | note.writtenBy = "author " + j + " " + z; 119 | page.notes.Add(note); 120 | } 121 | book.pages.AddLast(page); 122 | } 123 | return book; 124 | } 125 | } 126 | [DataContract] 127 | public enum Genre 128 | { 129 | [DataMember] 130 | Action, 131 | [DataMember] 132 | Romance, 133 | [DataMember] 134 | Comedy, 135 | [DataMember] 136 | SciFi 137 | } 138 | [DataContract] 139 | public class Page : IEquatable 140 | { 141 | public Page() 142 | { 143 | notes = new List(); 144 | identity = Guid.NewGuid(); 145 | } 146 | [DataMember] 147 | public string text { get; set; } 148 | [DataMember] 149 | public List notes { get; set; } 150 | [DataMember] 151 | public Guid identity { get; set; } 152 | public override int GetHashCode() { return identity.GetHashCode(); } 153 | public override bool Equals(object obj) { return Equals(obj as Page); } 154 | public bool Equals(Page other) 155 | { 156 | return other != null 157 | && other.text == this.text 158 | && Enumerable.SequenceEqual(other.notes, this.notes) 159 | && other.identity == this.identity; 160 | } 161 | } 162 | [DataContract] 163 | public class Footnote : Note, IEquatable 164 | { 165 | [DataMember] 166 | public string note { get; set; } 167 | [DataMember] 168 | public string writtenBy { get; set; } 169 | [DataMember] 170 | public DateTime createadAt { get; set; } 171 | [DataMember] 172 | public long index { get; set; } 173 | public override int GetHashCode() { return (int)index; } 174 | public override bool Equals(object obj) { return Equals(obj as Footnote); } 175 | public bool Equals(Footnote other) 176 | { 177 | return other != null && other.note == this.note && other.writtenBy == this.writtenBy 178 | && other.createadAt == this.createadAt && other.index == this.index; 179 | } 180 | } 181 | [DataContract] 182 | public class Headnote : Note, IEquatable 183 | { 184 | [DataMember] 185 | public string note { get; set; } 186 | [DataMember] 187 | public string writtenBy { get; set; } 188 | [DataMember] 189 | public DateTime? modifiedAt { get; set; } 190 | public override int GetHashCode() { return (modifiedAt ?? DateTime.MinValue).GetHashCode(); } 191 | public override bool Equals(object obj) { return Equals(obj as Headnote); } 192 | public bool Equals(Headnote other) 193 | { 194 | return other != null && other.note == this.note && other.writtenBy == this.writtenBy 195 | && other.modifiedAt == this.modifiedAt; 196 | } 197 | } 198 | public interface Note 199 | { 200 | string note { get; set; } 201 | string writtenBy { get; set; } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /Benchmark/Models.Small.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace JsonBenchmark.Models.Small 5 | { 6 | [DataContract] 7 | public class Message : IEquatable 8 | { 9 | [DataMember(Order = 1)] 10 | public string message { get; set; } 11 | [DataMember(Order = 2)] 12 | public int version { get; set; } 13 | public override int GetHashCode() { return version; } 14 | public override bool Equals(object obj) { return base.Equals(obj as Message); } 15 | public bool Equals(Message other) 16 | { 17 | return other != null && other.message == this.message && other.version == this.version; 18 | } 19 | public static T Factory(int i) where T : new() 20 | { 21 | dynamic instance = new T(); 22 | instance.message = "some message " + i; 23 | instance.version = i; 24 | return instance; 25 | } 26 | } 27 | [DataContract] 28 | public class Complex : IEquatable 29 | { 30 | [DataMember(Order = 1)] 31 | public decimal x { get; set; } 32 | [DataMember(Order = 2)] 33 | public float y { get; set; } 34 | [DataMember(Order = 3)] 35 | public long z { get; set; } 36 | public override int GetHashCode() { return (int)z; } 37 | public override bool Equals(object obj) { return Equals(obj as Complex); } 38 | public bool Equals(Complex other) 39 | { 40 | return other != null && other.x == this.x && other.y == this.y && other.z == this.z; 41 | } 42 | public static T Factory(int i) where T : new() 43 | { 44 | dynamic instance = new T(); 45 | instance.x = i / 1000m; 46 | instance.y = -i / 1000f; 47 | instance.z = i; 48 | return instance; 49 | } 50 | } 51 | [DataContract] 52 | public class Post : IEquatable 53 | { 54 | private static DateTime NOW = DateTime.UtcNow; 55 | 56 | [DataMember(Order = 2)] 57 | public Guid ID { get; set; } 58 | [DataMember(Order = 3)] 59 | public string title { get; set; } 60 | [DataMember(Order = 4)] 61 | public bool active { get; set; } 62 | [DataMember(Order = 5)] 63 | public DateTime created { get; set; } 64 | public override int GetHashCode() { return ID.GetHashCode(); } 65 | public override bool Equals(object obj) { return Equals(obj as Post); } 66 | public bool Equals(Post other) 67 | { 68 | return other != null && other.ID == this.ID && other.title == this.title 69 | && other.active == this.active && other.created == this.created; 70 | } 71 | public static T Factory(int i) where T : new() 72 | { 73 | dynamic instance = new T(); 74 | instance.ID = Guid.NewGuid(); 75 | instance.title = "some title " + i; 76 | instance.active = i % 2 == 0; 77 | instance.created = NOW.AddMinutes(i).Date; 78 | return instance; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Benchmark/Models.Standard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.Serialization; 5 | 6 | namespace JsonBenchmark.Models.Standard 7 | { 8 | [DataContract] 9 | public enum PostState 10 | { 11 | [DataMember] 12 | Draft, 13 | [DataMember] 14 | Published, 15 | [DataMember] 16 | Hidden, 17 | } 18 | 19 | [DataContract] 20 | public class DeletePost : IEquatable 21 | { 22 | private static DateTime NOW = DateTime.UtcNow; 23 | private static readonly Guid[] GUIDS = Enumerable.Range(0, 100).Select(it => Guid.NewGuid()).ToArray(); 24 | 25 | [DataMember(Order = 1)] 26 | public int postID { get; set; } 27 | [DataMember(Order = 2)] 28 | public Guid? referenceId { get; set; } 29 | [DataMember(Order = 3)] 30 | public DateTime lastModified { get; set; } 31 | [DataMember(Order = 4)] 32 | public long deletedBy { get; set; } 33 | [DataMember(Order = 5)] 34 | public string reason { get; set; } 35 | [DataMember(Order = 6)] 36 | public long[] versions { get; set; } 37 | [DataMember(Order = 7)] 38 | public PostState? state { get; set; } 39 | [DataMember(Order = 8)] 40 | public List votes { get; set; } 41 | public override int GetHashCode() { return postID; } 42 | public override bool Equals(object obj) { return Equals(obj as DeletePost); } 43 | public bool Equals(DeletePost other) 44 | { 45 | return other != null && other.postID == this.postID && other.referenceId == this.referenceId 46 | && other.lastModified == this.lastModified && other.deletedBy == this.deletedBy 47 | && other.reason == this.reason 48 | && (other.versions == this.versions || other.versions != null && Enumerable.SequenceEqual(other.versions, this.versions)) 49 | && other.state == this.state 50 | && (other.votes == this.votes || other.votes != null && Enumerable.SequenceEqual(other.votes, this.votes)); 51 | } 52 | public static TD Factory(int i, Func cast) 53 | where TD : new() 54 | where TS : struct 55 | { 56 | dynamic delete = new TD(); 57 | delete.postID = i; 58 | delete.deletedBy = i / 100; 59 | delete.lastModified = NOW.AddSeconds(i); 60 | delete.reason = "no reason"; 61 | if (i % 3 == 0) delete.referenceId = GUIDS[i % 100]; 62 | if (i % 5 == 0) delete.state = cast(i % 3); 63 | if (i % 7 == 0) 64 | { 65 | delete.versions = new long[i % 100 + 1];//ProtoBuf hack - always add object since Protobuf can't differentiate 66 | for (int x = 0; x <= i % 100; x++) 67 | delete.versions[x] = i * x + x; 68 | } 69 | if (i % 2 == 0 && i % 10 != 0) 70 | { 71 | delete.votes = new List(); 72 | for (int j = 0; j < i % 10; j++) 73 | delete.votes.Add((i + j) % 3 == 0 ? true : j % 2 == 0 ? (bool?)false : null); 74 | } 75 | return delete; 76 | } 77 | } 78 | [DataContract] 79 | public class Post : IEquatable 80 | { 81 | private static DateTime NOW = DateTime.UtcNow; 82 | private static DateTime TODAY = DateTime.UtcNow.Date; 83 | private static string[][] TAGS = new[] { new string[0], new[] { "JSON" }, new[] { ".NET", "Java", "benchmark" } }; 84 | 85 | public Post() 86 | { 87 | comments = new List(); 88 | } 89 | 90 | [DataMember(Order = 2)] 91 | public int ID { get; set; } 92 | [DataMember(Order = 3)] 93 | public string title { get; set; } 94 | [DataMember(Order = 4)] 95 | public string text { get; set; } 96 | [DataMember(Order = 5)] 97 | public DateTime created { get; set; } 98 | [DataMember(Order = 6)] 99 | public HashSet tags { get; set; } 100 | [DataMember(Order = 7)] 101 | public DateTime? approved { get; set; } 102 | [DataMember(Order = 8)] 103 | public List comments { get; set; } 104 | [DataMember(Order = 9)] 105 | public Vote votes { get; set; } 106 | [DataMember(Order = 10)] 107 | public List notes { get; set; } 108 | [DataMember(Order = 11)] 109 | public PostState state { get; set; } 110 | public override int GetHashCode() { return ID; } 111 | public override bool Equals(object obj) { return Equals(obj as Post); } 112 | public bool Equals(Post other) 113 | { 114 | var otherTags = other == null || other.tags == null ? null : other.tags.ToList(); 115 | var thisTags = this.tags != null ? this.tags.ToList() : null; 116 | if (thisTags != null) thisTags.Sort(); 117 | if (otherTags != null) otherTags.Sort(); 118 | return other != null && other.ID == this.ID && other.title == this.title 119 | && other.text == this.text && other.created == this.created 120 | && (otherTags == thisTags || otherTags != null && thisTags != null && Enumerable.SequenceEqual(otherTags, thisTags)) 121 | && other.approved == this.approved 122 | && Enumerable.SequenceEqual(other.comments, this.comments) 123 | && other.votes.Equals(this.votes) 124 | && (other.notes == this.notes || other.notes != null && Enumerable.SequenceEqual(other.notes, this.notes)) 125 | && other.state == this.state; 126 | } 127 | public static TP Factory(int i, Func cast) 128 | where TP : new() 129 | where TV : new() 130 | where TC : new() 131 | where TS : struct 132 | { 133 | dynamic post = new TP(); 134 | post.ID = -i; 135 | post.approved = i % 2 == 0 ? null : (DateTime?)NOW.AddMilliseconds(i); 136 | dynamic votes = new TV(); 137 | votes.downvote = i / 3; 138 | votes.upvote = i / 2; 139 | post.votes = votes; 140 | post.text = "some text describing post " + i; 141 | post.title = "post title " + i; 142 | post.state = cast(i % 3); 143 | post.tags = new HashSet(TAGS[i % 3]); 144 | post.created = TODAY.AddDays(i); 145 | for (int j = 0; j < i % 100; j++) 146 | { 147 | dynamic comment = new TC(); 148 | comment.created = TODAY.AddDays(i + j); 149 | comment.message = "comment number " + i + " for " + j; 150 | dynamic v = new TV(); 151 | v.upvote = j; 152 | v.downvote = j * 2; 153 | comment.votes = v; 154 | comment.approved = j % 3 != 0 ? null : (DateTime?)NOW.AddMilliseconds(i); 155 | comment.user = "some random user " + i; 156 | post.comments.Add(comment); 157 | } 158 | return post; 159 | } 160 | } 161 | [DataContract] 162 | public class Comment : IEquatable 163 | { 164 | [DataMember(Order = 4)] 165 | public DateTime created { get; set; } 166 | [DataMember(Order = 5)] 167 | public DateTime? approved { get; set; } 168 | [DataMember(Order = 6)] 169 | public string user { get; set; } 170 | [DataMember(Order = 7)] 171 | public string message { get; set; } 172 | [DataMember(Order = 8)] 173 | public Vote votes { get; set; } 174 | public override int GetHashCode() { return created.GetHashCode(); } 175 | public override bool Equals(object obj) { return Equals(obj as Comment); } 176 | public bool Equals(Comment other) 177 | { 178 | return other != null 179 | && other.created == this.created && other.approved == this.approved && other.user == this.user 180 | && other.message == this.message && other.votes.Equals(this.votes); 181 | } 182 | } 183 | [DataContract] 184 | public class Vote : IEquatable 185 | { 186 | [DataMember(Order = 1)] 187 | public int upvote { get; set; } 188 | [DataMember(Order = 2)] 189 | public int downvote { get; set; } 190 | public override int GetHashCode() { return upvote ^ downvote; } 191 | public override bool Equals(object obj) { return Equals(obj as Vote); } 192 | public bool Equals(Vote other) 193 | { 194 | return other != null && other.upvote == this.upvote && other.downvote == this.downvote; 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /Benchmark/Program.cs: -------------------------------------------------------------------------------- 1 | using Revenj.Utility; 2 | using System; 3 | using System.Diagnostics; 4 | 5 | namespace JsonBenchmark 6 | { 7 | class Program 8 | { 9 | enum BenchTarget 10 | { 11 | RevenjNewtonsoftJson, RevenjJsonFull, RevenjJsonMinimal, 12 | NewtonsoftJson, Jil, fastJSON, ServiceStack, BondJson, NetJSON, 13 | ProtoBuf, BondBinary, Utf8Json 14 | } 15 | 16 | enum BenchSize 17 | { 18 | Small, Standard, Large 19 | } 20 | 21 | enum BenchType 22 | { 23 | Serialization, Both, None, Check 24 | } 25 | 26 | static int Main(string[] args) 27 | { 28 | //args = new[] { "BondBinary", "Standard", "Check", "100" }; 29 | //args = new[] { "RevenjNewtonsoftJson", "Large", "Serialization", "100" }; 30 | var gc0 = GC.CollectionCount(0); 31 | var gc1 = GC.CollectionCount(1); 32 | var gc2 = GC.CollectionCount(2); 33 | if (args.Length != 4) 34 | { 35 | Console.WriteLine( 36 | "Expected usage: JsonBenchamrk.exe ({0}) ({1}) ({2}) repeat", 37 | string.Join(" | ", Enum.GetNames(typeof(BenchTarget))), 38 | string.Join(" | ", Enum.GetNames(typeof(BenchSize))), 39 | string.Join(" | ", Enum.GetNames(typeof(BenchType)))); 40 | return -1; 41 | } 42 | BenchTarget target; 43 | if (!Enum.TryParse(args[0], out target)) 44 | { 45 | Console.WriteLine("Unknown target found: " + args[0] + ". Supported targets: " + string.Join(" | ", Enum.GetNames(typeof(BenchTarget)))); 46 | return -2; 47 | } 48 | BenchSize size; 49 | if (!Enum.TryParse(args[1], out size)) 50 | { 51 | Console.WriteLine("Unknown size found: " + args[1] + ". Supported size: " + string.Join(" | ", Enum.GetNames(typeof(BenchSize)))); 52 | return -3; 53 | } 54 | BenchType type; 55 | if (!Enum.TryParse(args[2], out type)) 56 | { 57 | Console.WriteLine("Unknown type found: " + args[2] + ". Supported types: " + string.Join(" | ", Enum.GetNames(typeof(BenchType)))); 58 | return -4; 59 | } 60 | int repeat; 61 | if (!int.TryParse(args[3], out repeat)) 62 | { 63 | Console.WriteLine("Invalid repeat parameter: " + args[3]); 64 | return -5; 65 | } 66 | Action serialize; 67 | Func deserialize; 68 | switch (target) 69 | { 70 | case BenchTarget.NewtonsoftJson: 71 | LibrarySetup.SetupNewtonsoftJson(out serialize, out deserialize); 72 | break; 73 | case BenchTarget.RevenjNewtonsoftJson: 74 | LibrarySetup.SetupNewtonsoftJson(out serialize, out deserialize); 75 | break; 76 | case BenchTarget.BondJson: 77 | LibrarySetup.SetupBondJson(out serialize, out deserialize); 78 | break; 79 | case BenchTarget.BondBinary: 80 | LibrarySetup.SetupBondBinary(out serialize, out deserialize); 81 | break; 82 | case BenchTarget.Jil: 83 | LibrarySetup.SetupJil(out serialize, out deserialize); 84 | break; 85 | case BenchTarget.fastJSON: 86 | LibrarySetup.SetupFastJson(out serialize, out deserialize); 87 | break; 88 | case BenchTarget.ServiceStack: 89 | LibrarySetup.SetupServiceStack(out serialize, out deserialize); 90 | break; 91 | case BenchTarget.NetJSON: 92 | LibrarySetup.SetupNetJSON(out serialize, out deserialize); 93 | break; 94 | case BenchTarget.Utf8Json: 95 | LibrarySetup.SetupUtf8Json(out serialize, out deserialize); 96 | break; 97 | case BenchTarget.ProtoBuf: 98 | LibrarySetup.SetupProtobuf(out serialize, out deserialize); 99 | break; 100 | case BenchTarget.RevenjJsonFull: 101 | LibrarySetup.SetupRevenj(out serialize, out deserialize, false); 102 | break; 103 | case BenchTarget.RevenjJsonMinimal: 104 | LibrarySetup.SetupRevenj(out serialize, out deserialize, true); 105 | break; 106 | default: 107 | Console.WriteLine("Unwired bench type: " + type); 108 | return -123; 109 | } 110 | var ms = new ChunkedMemoryStream(); 111 | switch (size) 112 | { 113 | case BenchSize.Small: 114 | try 115 | { 116 | if (target == BenchTarget.BondBinary || target == BenchTarget.BondJson) 117 | { 118 | Func factory1 = 119 | i => Models.Small.Message.Factory(i); 120 | Func factory2 = 121 | i => Models.Small.Complex.Factory(i); 122 | Func factory3 = 123 | i => Models.Small.Post.Factory(i); 124 | RunLoop(repeat, serialize, deserialize, type, ms, factory1); 125 | RunLoop(repeat, serialize, deserialize, type, ms, factory2); 126 | RunLoop(repeat, serialize, deserialize, type, ms, factory3); 127 | } 128 | else if (target == BenchTarget.RevenjJsonFull || target == BenchTarget.RevenjJsonMinimal 129 | || target == BenchTarget.RevenjNewtonsoftJson) 130 | { 131 | Func factory1 = i => Models.Small.Message.Factory(i); 132 | Func factory2 = i => Models.Small.Complex.Factory(i); 133 | Func factory3 = i => Models.Small.Post.Factory(i); 134 | RunLoop(repeat, serialize, deserialize, type, ms, factory1); 135 | RunLoop(repeat, serialize, deserialize, type, ms, factory2); 136 | RunLoop(repeat, serialize, deserialize, type, ms, factory3); 137 | } 138 | else 139 | { 140 | Func factory1 = i => Models.Small.Message.Factory(i); 141 | Func factory2 = i => Models.Small.Complex.Factory(i); 142 | Func factory3 = i => Models.Small.Post.Factory(i); 143 | RunLoop(repeat, serialize, deserialize, type, ms, factory1); 144 | RunLoop(repeat, serialize, deserialize, type, ms, factory2); 145 | RunLoop(repeat, serialize, deserialize, type, ms, factory3); 146 | } 147 | } 148 | catch (Exception ex) 149 | { 150 | ReportStatsAndRestart(null, -1, repeat); 151 | ReportStatsAndRestart(null, -1, repeat); 152 | ReportStatsAndRestart(null, -1, repeat); 153 | Console.WriteLine("error"); 154 | Console.WriteLine(ex.Message); 155 | return -41; 156 | } 157 | break; 158 | case BenchSize.Standard: 159 | try 160 | { 161 | if (target == BenchTarget.BondBinary || target == BenchTarget.BondJson) 162 | { 163 | Func cast = i => (StandardObjects.Bond.PostState)i; 164 | Func factory1 = 165 | i => Models.Standard.DeletePost.Factory(i, cast); 166 | Func factory2 = 167 | i => Models.Standard.Post.Factory(i, cast); 168 | RunLoop(repeat, serialize, deserialize, type, ms, factory1); 169 | RunLoop(repeat, serialize, deserialize, type, ms, factory2); 170 | } 171 | else if (target == BenchTarget.RevenjJsonFull || target == BenchTarget.RevenjJsonMinimal 172 | || target == BenchTarget.RevenjNewtonsoftJson) 173 | { 174 | Func cast = i => (StandardObjects.PostState)i; 175 | Func factory1 = 176 | i => Models.Standard.DeletePost.Factory(i, cast); 177 | Func factory2 = 178 | i => Models.Standard.Post.Factory(i, cast); 179 | RunLoop(repeat, serialize, deserialize, type, ms, factory1); 180 | RunLoop(repeat, serialize, deserialize, type, ms, factory2); 181 | } 182 | else 183 | { 184 | Func cast = i => (Models.Standard.PostState)i; 185 | Func factory1 = i => Models.Standard.DeletePost.Factory(i, cast); 186 | Func factory2 = 187 | i => Models.Standard.Post.Factory(i, cast); 188 | RunLoop(repeat, serialize, deserialize, type, ms, factory1); 189 | RunLoop(repeat, serialize, deserialize, type, ms, factory2); 190 | } 191 | } 192 | catch (Exception ex) 193 | { 194 | ReportStatsAndRestart(null, -1, repeat); 195 | ReportStatsAndRestart(null, -1, repeat); 196 | Console.WriteLine("error"); 197 | Console.WriteLine(ex.Message); 198 | return -42; 199 | } 200 | break; 201 | default: 202 | try 203 | { 204 | if (target == BenchTarget.RevenjJsonFull || target == BenchTarget.RevenjJsonMinimal 205 | || target == BenchTarget.RevenjNewtonsoftJson) 206 | { 207 | Func cast = i => (LargeObjects.Genre)i; 208 | Func factory = 209 | i => Models.Large.Book.Factory(i, cast); 210 | RunLoop(repeat, serialize, deserialize, type, ms, factory); 211 | } 212 | else 213 | { 214 | Func cast = i => (Models.Large.Genre)i; 215 | Func factory = 216 | i => Models.Large.Book.Factory(i, cast); 217 | RunLoop(repeat, serialize, deserialize, type, ms, factory); 218 | } 219 | } 220 | catch (Exception ex) 221 | { 222 | ReportStatsAndRestart(null, -1, repeat); 223 | Console.WriteLine("error"); 224 | Console.WriteLine(ex.Message); 225 | return -43; 226 | } 227 | break; 228 | } 229 | //Console.WriteLine("GC0: " + (GC.CollectionCount(0) - gc0)); 230 | //Console.WriteLine("GC1: " + (GC.CollectionCount(1) - gc1)); 231 | //Console.WriteLine("GC2: " + (GC.CollectionCount(2) - gc2)); 232 | return 0; 233 | } 234 | 235 | static void ReportStatsAndRestart(Stopwatch sw, long size, int incorrect) 236 | { 237 | Console.WriteLine("duration = " + (sw != null ? sw.ElapsedMilliseconds : -1)); 238 | Console.WriteLine("size = " + size); 239 | Console.WriteLine("invalid deserialization = " + incorrect); 240 | if (sw != null) 241 | sw.Restart(); 242 | } 243 | 244 | private static void RunLoop( 245 | int repeat, 246 | Action serialize, 247 | Func deserialize, 248 | BenchType type, 249 | ChunkedMemoryStream ms, 250 | Func factory) where T : IEquatable 251 | { 252 | var sw = Stopwatch.StartNew(); 253 | var incorrect = 0; 254 | long size = 0; 255 | for (int i = 0; i < repeat; i++) 256 | { 257 | ms.SetLength(0); 258 | var instance = factory(i); 259 | if (type == BenchType.None) continue; 260 | serialize(instance, ms); 261 | size += ms.Position; 262 | if (type == BenchType.Both || type == BenchType.Check) 263 | { 264 | ms.Position = 0; 265 | var deser = (T)deserialize(ms, typeof(T)); 266 | if (type == BenchType.Check && !instance.Equals(deser)) 267 | { 268 | incorrect++; 269 | //throw new SerializationException("not equal"); 270 | } 271 | } 272 | } 273 | ReportStatsAndRestart(sw, size, incorrect); 274 | } 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /Benchmark/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("JsonBenchmark")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Nova generacija softvera")] 12 | [assembly: AssemblyProduct("JsonBenchmark")] 13 | [assembly: AssemblyCopyright("Copyright © Nova generacija softvera 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a0f5b48e-00c8-40ff-b0b2-b2c3fc5e590e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Benchmark/SmallObjects.dsl: -------------------------------------------------------------------------------- 1 | module SmallObjects { 2 | value Message { 3 | string message; 4 | int version; 5 | } 6 | value Post { 7 | guid ID { 8 | //otherwise we will get a new guid as default 9 | default c# 'System.Guid.Empty'; 10 | default Java 'com.dslplatform.json.UUIDConverter.MIN_UUID'; 11 | } 12 | string title; 13 | bool active; 14 | date created { 15 | //otherwise we will get current date 16 | default c# 'System.DateTime.MinValue'; 17 | default Java 'com.dslplatform.json.JavaTimeConverter.MIN_LOCAL_DATE'; 18 | } 19 | } 20 | value Complex { 21 | decimal x; 22 | float y; 23 | long z; 24 | } 25 | } -------------------------------------------------------------------------------- /Benchmark/StandardObjects.dsl: -------------------------------------------------------------------------------- 1 | module StandardObjects { 2 | value DeletePost { 3 | int postID; 4 | guid? referenceId; 5 | timestamp lastModified { 6 | //otherwise we will get current timestamp 7 | default c# 'System.DateTime.MinValue'; 8 | default Java 'com.dslplatform.json.JavaTimeConverter.MIN_DATE_TIME_UTC'; 9 | } 10 | long deletedBy; 11 | string? reason; 12 | long[]? versions; //Issue: ProtoBuf doesn't differentiate empty array from null 13 | PostState? state; 14 | list? votes; //Issue: list required Protobuf modification 15 | } 16 | enum PostState { 17 | Draft; 18 | Published; 19 | Hidden; 20 | } 21 | value Post { 22 | int ID; 23 | string title; 24 | string text; 25 | date created { 26 | //otherwise we will get current date 27 | default c# 'System.DateTime.MinValue'; 28 | default Java 'com.dslplatform.json.JavaTimeConverter.MIN_LOCAL_DATE'; 29 | } 30 | Set tags; 31 | timestamp? approved; 32 | List comments; 33 | Vote votes; 34 | List? notes; 35 | PostState state; 36 | } 37 | value Comment { 38 | date created { 39 | //otherwise we will get current date 40 | default c# 'System.DateTime.MinValue'; 41 | default Java 'com.dslplatform.json.JavaTimeConverter.MIN_LOCAL_DATE'; 42 | } 43 | timestamp? approved; 44 | string? user; 45 | string message; 46 | Vote votes; 47 | } 48 | value Vote { 49 | int upvote; 50 | int downvote; 51 | } 52 | } -------------------------------------------------------------------------------- /Benchmark/bond/BondConverters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace SmallObjects.Bond 5 | { 6 | partial class Message : IEquatable 7 | { 8 | public bool Equals(Message other) 9 | { 10 | return other != null && other.message == this.message && other.version == this.version; 11 | } 12 | } 13 | partial class Complex : IEquatable 14 | { 15 | public bool Equals(Complex other) 16 | { 17 | return other != null && other.x == this.x && other.y == this.y && other.z == this.z; 18 | } 19 | } 20 | partial class Post : IEquatable 21 | { 22 | public bool Equals(Post other) 23 | { 24 | return other != null && other.ID == this.ID && other.created == this.created 25 | && other.title == this.title && other.active == this.active; 26 | } 27 | } 28 | public static class BondTypeAliasConverter 29 | { 30 | public static decimal Convert(ArraySegment value, decimal unused) 31 | { 32 | var bits = new int[value.Count / sizeof(int)]; 33 | Buffer.BlockCopy(value.Array, value.Offset, bits, 0, bits.Length * sizeof(int)); 34 | return new decimal(bits); 35 | } 36 | 37 | public static ArraySegment Convert(decimal value, ArraySegment unused) 38 | { 39 | var bits = decimal.GetBits(value); 40 | var data = new byte[bits.Length * sizeof(int)]; 41 | Buffer.BlockCopy(bits, 0, data, 0, data.Length); 42 | return new ArraySegment(data); 43 | } 44 | public static long Convert(DateTime value, long unused) 45 | { 46 | return value.Ticks; 47 | } 48 | 49 | public static DateTime Convert(long value, DateTime unused) 50 | { 51 | return new DateTime(value); 52 | } 53 | public static Guid Convert(ArraySegment value, Guid unused) 54 | { 55 | var bytes = new byte[value.Count]; 56 | Array.Copy(value.Array, value.Offset, bytes, 0, bytes.Length); 57 | return new Guid(bytes); 58 | } 59 | 60 | public static ArraySegment Convert(Guid value, ArraySegment unused) 61 | { 62 | var bytes = value.ToByteArray(); 63 | return new ArraySegment(bytes); 64 | } 65 | } 66 | } 67 | namespace StandardObjects.Bond 68 | { 69 | partial class Vote : IEquatable 70 | { 71 | public bool Equals(Vote other) 72 | { 73 | return other != null && other.upvote == this.upvote && other.downvote == this.downvote; 74 | } 75 | } 76 | partial class Comment : IEquatable 77 | { 78 | public bool Equals(Comment other) 79 | { 80 | return other != null 81 | && other.created == this.created && other.approved == this.approved && other.user == this.user 82 | && other.message == this.message && other.votes.Equals(this.votes); 83 | } 84 | } 85 | partial class DeletePost : IEquatable 86 | { 87 | public bool Equals(DeletePost other) 88 | { 89 | return other != null && other.postID == this.postID && other.referenceId == this.referenceId 90 | && other.lastModified == this.lastModified && other.deletedBy == this.deletedBy 91 | && other.reason == this.reason 92 | && (other.versions == this.versions || other.versions != null && Enumerable.SequenceEqual(other.versions, this.versions)) 93 | && other.state == this.state 94 | && (other.votes == this.votes || other.votes != null && Enumerable.SequenceEqual(other.votes, this.votes)); 95 | } 96 | } 97 | partial class Post : IEquatable 98 | { 99 | public bool Equals(Post other) 100 | { 101 | var otherTags = other == null || other.tags == null ? null : other.tags.ToList(); 102 | var thisTags = this.tags != null ? this.tags.ToList() : null; 103 | if (thisTags != null) thisTags.Sort(); 104 | if (otherTags != null) otherTags.Sort(); 105 | return other != null && other.ID == this.ID && other.title == this.title 106 | && other.text == this.text && other.created == this.created 107 | && (otherTags == thisTags || otherTags != null && thisTags != null && Enumerable.SequenceEqual(otherTags, thisTags)) 108 | && other.approved == this.approved 109 | && Enumerable.SequenceEqual(other.comments, this.comments) 110 | && other.votes.Equals(this.votes) 111 | && (other.notes == this.notes || other.notes != null && Enumerable.SequenceEqual(other.notes, this.notes)) 112 | && other.state == this.state; 113 | } 114 | } 115 | public static class BondTypeAliasConverter 116 | { 117 | public static decimal Convert(ArraySegment value, decimal unused) 118 | { 119 | var bits = new int[value.Count / sizeof(int)]; 120 | Buffer.BlockCopy(value.Array, value.Offset, bits, 0, bits.Length * sizeof(int)); 121 | return new decimal(bits); 122 | } 123 | 124 | public static ArraySegment Convert(decimal value, ArraySegment unused) 125 | { 126 | var bits = decimal.GetBits(value); 127 | var data = new byte[bits.Length * sizeof(int)]; 128 | Buffer.BlockCopy(bits, 0, data, 0, data.Length); 129 | return new ArraySegment(data); 130 | } 131 | public static long Convert(DateTime value, long unused) 132 | { 133 | return value.Ticks; 134 | } 135 | 136 | public static DateTime Convert(long value, DateTime unused) 137 | { 138 | return new DateTime(value); 139 | } 140 | public static Guid Convert(ArraySegment value, Guid unused) 141 | { 142 | var bytes = new byte[value.Count]; 143 | Array.Copy(value.Array, value.Offset, bytes, 0, bytes.Length); 144 | return new Guid(bytes); 145 | } 146 | 147 | public static ArraySegment Convert(Guid value, ArraySegment unused) 148 | { 149 | var bytes = value.ToByteArray(); 150 | return new ArraySegment(bytes); 151 | } 152 | } 153 | 154 | } -------------------------------------------------------------------------------- /Benchmark/bond/SmallObjects.bond: -------------------------------------------------------------------------------- 1 | namespace SmallObjects.Bond 2 | 3 | using DECIMAL = blob; 4 | using DATETIME = int64; 5 | using GUID = blob; 6 | 7 | struct Message { 8 | 1: string message; 9 | 2: int32 version; 10 | } 11 | 12 | struct Post { 13 | 1: GUID ID; 14 | 2: string title; 15 | 3: bool active; 16 | 4: DATETIME created; 17 | } 18 | 19 | struct Complex { 20 | 1: DECIMAL x; 21 | 2: float y; 22 | 3: int64 z; 23 | } 24 | -------------------------------------------------------------------------------- /Benchmark/bond/SmallObjects_types.cs: -------------------------------------------------------------------------------- 1 | 2 | //------------------------------------------------------------------------------ 3 | // This code was generated by a tool. 4 | // 5 | // Tool : Bond Compiler 3.05 6 | // File : SmallObjects_types.cs 7 | // 8 | // Changes to this file may cause incorrect behavior and will be lost when 9 | // the code is regenerated. 10 | // 11 | //------------------------------------------------------------------------------ 12 | 13 | 14 | #region ReSharper warnings 15 | // ReSharper disable PartialTypeWithSinglePart 16 | // ReSharper disable RedundantNameQualifier 17 | // ReSharper disable InconsistentNaming 18 | // ReSharper disable CheckNamespace 19 | // ReSharper disable UnusedParameter.Local 20 | // ReSharper disable RedundantUsingDirective 21 | #endregion 22 | 23 | namespace SmallObjects.Bond 24 | { 25 | using System.Collections.Generic; 26 | 27 | [global::Bond.Schema] 28 | [System.CodeDom.Compiler.GeneratedCode("gbc", "3.05")] 29 | public partial class Message 30 | { 31 | [global::Bond.Id(1)] 32 | public string message { get; set; } 33 | 34 | [global::Bond.Id(2)] 35 | public int version { get; set; } 36 | 37 | public Message() 38 | : this("SmallObjects.Bond.Message", "Message") 39 | {} 40 | 41 | protected Message(string fullName, string name) 42 | { 43 | message = string.Empty; 44 | } 45 | } 46 | 47 | [global::Bond.Schema] 48 | [System.CodeDom.Compiler.GeneratedCode("gbc", "3.05")] 49 | public partial class Post 50 | { 51 | [global::Bond.Id(1), global::Bond.Type(typeof(global::Bond.Tag.blob))] 52 | public System.Guid ID { get; set; } 53 | 54 | [global::Bond.Id(2)] 55 | public string title { get; set; } 56 | 57 | [global::Bond.Id(3)] 58 | public bool active { get; set; } 59 | 60 | [global::Bond.Id(4), global::Bond.Type(typeof(long))] 61 | public System.DateTime created { get; set; } 62 | 63 | public Post() 64 | : this("SmallObjects.Bond.Post", "Post") 65 | {} 66 | 67 | protected Post(string fullName, string name) 68 | { 69 | ID = new System.Guid(); 70 | title = string.Empty; 71 | created = new System.DateTime(); 72 | } 73 | } 74 | 75 | [global::Bond.Schema] 76 | [System.CodeDom.Compiler.GeneratedCode("gbc", "3.05")] 77 | public partial class Complex 78 | { 79 | [global::Bond.Id(1), global::Bond.Type(typeof(global::Bond.Tag.blob))] 80 | public decimal x { get; set; } 81 | 82 | [global::Bond.Id(2)] 83 | public float y { get; set; } 84 | 85 | [global::Bond.Id(3)] 86 | public long z { get; set; } 87 | 88 | public Complex() 89 | : this("SmallObjects.Bond.Complex", "Complex") 90 | {} 91 | 92 | protected Complex(string fullName, string name) 93 | { 94 | x = new decimal(); 95 | } 96 | } 97 | } // SmallObjects.Bond 98 | -------------------------------------------------------------------------------- /Benchmark/bond/StandardObjects.bond: -------------------------------------------------------------------------------- 1 | namespace StandardObjects.Bond 2 | 3 | using DATETIME = int64; 4 | using GUID = blob; 5 | using LongArray = vector; 6 | 7 | enum PostState { 8 | Draft, 9 | Published, 10 | Hidden 11 | } 12 | struct Vote { 13 | 1: int32 upvote; 14 | 2: int32 downvote; 15 | } 16 | struct Comment { 17 | 4: DATETIME created; 18 | 5: nullable approved; 19 | 6: nullable user; 20 | 7: string message; 21 | 8: Vote votes; 22 | } 23 | struct DeletePost { 24 | 1: int32 postID; 25 | 2: nullable referenceId; 26 | 3: DATETIME lastModified; 27 | 4: int64 deletedBy; 28 | 5: nullable reason; 29 | 6: nullable versions; 30 | 7: nullable state; 31 | 8: nullable>> votes; 32 | } 33 | struct Post { 34 | 2: int32 ID; 35 | 3: string title; 36 | 4: string text; 37 | 5: DATETIME created; 38 | 6: set tags; 39 | 7: nullable approved; 40 | 8: vector comments; 41 | 9: Vote votes; 42 | 10: nullable> notes; 43 | 11: PostState state; 44 | } 45 | -------------------------------------------------------------------------------- /Benchmark/bond/StandardObjects_types.cs: -------------------------------------------------------------------------------- 1 | 2 | //------------------------------------------------------------------------------ 3 | // This code was generated by a tool. 4 | // 5 | // Tool : Bond Compiler 3.05 6 | // File : StandardObjects_types.cs 7 | // 8 | // Changes to this file may cause incorrect behavior and will be lost when 9 | // the code is regenerated. 10 | // 11 | //------------------------------------------------------------------------------ 12 | 13 | 14 | #region ReSharper warnings 15 | // ReSharper disable PartialTypeWithSinglePart 16 | // ReSharper disable RedundantNameQualifier 17 | // ReSharper disable InconsistentNaming 18 | // ReSharper disable CheckNamespace 19 | // ReSharper disable UnusedParameter.Local 20 | // ReSharper disable RedundantUsingDirective 21 | #endregion 22 | 23 | namespace StandardObjects.Bond 24 | { 25 | using System.Collections.Generic; 26 | 27 | 28 | [System.CodeDom.Compiler.GeneratedCode("gbc", "3.05")] 29 | public enum PostState 30 | { 31 | Draft, 32 | Published, 33 | Hidden, 34 | } 35 | 36 | [global::Bond.Schema] 37 | [System.CodeDom.Compiler.GeneratedCode("gbc", "3.05")] 38 | public partial class Vote 39 | { 40 | [global::Bond.Id(1)] 41 | public int upvote { get; set; } 42 | 43 | [global::Bond.Id(2)] 44 | public int downvote { get; set; } 45 | 46 | public Vote() 47 | : this("StandardObjects.Bond.Vote", "Vote") 48 | {} 49 | 50 | protected Vote(string fullName, string name) 51 | { 52 | 53 | } 54 | } 55 | 56 | [global::Bond.Schema] 57 | [System.CodeDom.Compiler.GeneratedCode("gbc", "3.05")] 58 | public partial class Comment 59 | { 60 | [global::Bond.Id(4), global::Bond.Type(typeof(long))] 61 | public System.DateTime created { get; set; } 62 | 63 | [global::Bond.Id(5), global::Bond.Type(typeof(global::Bond.Tag.nullable))] 64 | public System.DateTime? approved { get; set; } 65 | 66 | [global::Bond.Id(6), global::Bond.Type(typeof(global::Bond.Tag.nullable))] 67 | public string user { get; set; } 68 | 69 | [global::Bond.Id(7)] 70 | public string message { get; set; } 71 | 72 | [global::Bond.Id(8)] 73 | public Vote votes { get; set; } 74 | 75 | public Comment() 76 | : this("StandardObjects.Bond.Comment", "Comment") 77 | {} 78 | 79 | protected Comment(string fullName, string name) 80 | { 81 | created = new System.DateTime(); 82 | message = string.Empty; 83 | votes = new Vote(); 84 | } 85 | } 86 | 87 | [global::Bond.Schema] 88 | [System.CodeDom.Compiler.GeneratedCode("gbc", "3.05")] 89 | public partial class DeletePost 90 | { 91 | [global::Bond.Id(1)] 92 | public int postID { get; set; } 93 | 94 | [global::Bond.Id(2), global::Bond.Type(typeof(global::Bond.Tag.nullable))] 95 | public System.Guid referenceId { get; set; } 96 | 97 | [global::Bond.Id(3), global::Bond.Type(typeof(long))] 98 | public System.DateTime lastModified { get; set; } 99 | 100 | [global::Bond.Id(4)] 101 | public long deletedBy { get; set; } 102 | 103 | [global::Bond.Id(5), global::Bond.Type(typeof(global::Bond.Tag.nullable))] 104 | public string reason { get; set; } 105 | 106 | [global::Bond.Id(6), global::Bond.Type(typeof(global::Bond.Tag.nullable))] 107 | public long[] versions { get; set; } 108 | 109 | [global::Bond.Id(7), global::Bond.Type(typeof(global::Bond.Tag.nullable))] 110 | public PostState? state { get; set; } 111 | 112 | [global::Bond.Id(8), global::Bond.Type(typeof(global::Bond.Tag.nullable>>))] 113 | public List votes { get; set; } 114 | 115 | public DeletePost() 116 | : this("StandardObjects.Bond.DeletePost", "DeletePost") 117 | {} 118 | 119 | protected DeletePost(string fullName, string name) 120 | { 121 | lastModified = new System.DateTime(); 122 | } 123 | } 124 | 125 | [global::Bond.Schema] 126 | [System.CodeDom.Compiler.GeneratedCode("gbc", "3.05")] 127 | public partial class Post 128 | { 129 | [global::Bond.Id(2)] 130 | public int ID { get; set; } 131 | 132 | [global::Bond.Id(3)] 133 | public string title { get; set; } 134 | 135 | [global::Bond.Id(4)] 136 | public string text { get; set; } 137 | 138 | [global::Bond.Id(5), global::Bond.Type(typeof(long))] 139 | public System.DateTime created { get; set; } 140 | 141 | [global::Bond.Id(6)] 142 | public HashSet tags { get; set; } 143 | 144 | [global::Bond.Id(7), global::Bond.Type(typeof(global::Bond.Tag.nullable))] 145 | public System.DateTime? approved { get; set; } 146 | 147 | [global::Bond.Id(8)] 148 | public List comments { get; set; } 149 | 150 | [global::Bond.Id(9)] 151 | public Vote votes { get; set; } 152 | 153 | [global::Bond.Id(10), global::Bond.Type(typeof(global::Bond.Tag.nullable>))] 154 | public List notes { get; set; } 155 | 156 | [global::Bond.Id(11)] 157 | public PostState state { get; set; } 158 | 159 | public Post() 160 | : this("StandardObjects.Bond.Post", "Post") 161 | {} 162 | 163 | protected Post(string fullName, string name) 164 | { 165 | title = string.Empty; 166 | text = string.Empty; 167 | created = new System.DateTime(); 168 | tags = new HashSet(); 169 | comments = new List(); 170 | votes = new Vote(); 171 | state = new PostState(); 172 | } 173 | } 174 | } // StandardObjects.Bond 175 | -------------------------------------------------------------------------------- /Benchmark/lib/ServerModel.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/Benchmark/lib/ServerModel.dll -------------------------------------------------------------------------------- /Benchmark/lib/generated-model.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/Benchmark/lib/generated-model.jar -------------------------------------------------------------------------------- /Benchmark/lib/hr/ngs/benchmark/generated-model/1.6/generated-model-1.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/Benchmark/lib/hr/ngs/benchmark/generated-model/1.6/generated-model-1.6.jar -------------------------------------------------------------------------------- /Benchmark/lib/hr/ngs/benchmark/generated-model/1.6/generated-model-1.6.jar.md5: -------------------------------------------------------------------------------- 1 | f1e5f81effe26c21eee94543392ccef1 -------------------------------------------------------------------------------- /Benchmark/lib/hr/ngs/benchmark/generated-model/1.6/generated-model-1.6.jar.sha1: -------------------------------------------------------------------------------- 1 | 7051c6997e060476a6cb46c6a085c7c9bf6e8013 -------------------------------------------------------------------------------- /Benchmark/lib/hr/ngs/benchmark/generated-model/1.6/generated-model-1.6.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | hr.ngs.benchmark 6 | generated-model 7 | 1.6 8 | 9 | -------------------------------------------------------------------------------- /Benchmark/lib/hr/ngs/benchmark/generated-model/1.6/generated-model-1.6.pom.md5: -------------------------------------------------------------------------------- 1 | 867297cd6cce77ab7083728a33e24280 -------------------------------------------------------------------------------- /Benchmark/lib/hr/ngs/benchmark/generated-model/1.6/generated-model-1.6.pom.sha1: -------------------------------------------------------------------------------- 1 | c8462656a60cbe76f6cadaa74d458d3320f84452 -------------------------------------------------------------------------------- /Benchmark/lib/hr/ngs/benchmark/generated-model/maven-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | hr.ngs.benchmark 4 | generated-model 5 | 6 | 1.6 7 | 8 | 1.6 9 | 10 | 20160730135232 11 | 12 | 13 | -------------------------------------------------------------------------------- /Benchmark/lib/hr/ngs/benchmark/generated-model/maven-metadata.xml.md5: -------------------------------------------------------------------------------- 1 | 76bb43cfa44d97d215760df908099bf9 -------------------------------------------------------------------------------- /Benchmark/lib/hr/ngs/benchmark/generated-model/maven-metadata.xml.sha1: -------------------------------------------------------------------------------- 1 | 08d0501a71ed223785ef52d63b5448c9d6c7ce39 -------------------------------------------------------------------------------- /Benchmark/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | hr.ngs 5 | json-benchmark 6 | jar 7 | 1.6 8 | JSON Benchmark 9 | http://maven.apache.org 10 | 11 | 12 | 13 | project.local 14 | project 15 | file:${project.basedir}/lib 16 | 17 | 18 | 19 | 20 | 21 | com.dslplatform 22 | dsl-json-java8 23 | 1.1.2 24 | 25 | 26 | com.fasterxml.jackson.core 27 | jackson-databind 28 | 2.8.1 29 | 30 | 31 | com.fasterxml.jackson.datatype 32 | jackson-datatype-jsr310 33 | 2.8.1 34 | 35 | 36 | com.fasterxml.jackson.module 37 | jackson-module-afterburner 38 | 2.8.1 39 | 40 | 41 | io.advantageous.boon 42 | boon-json 43 | 0.6.6 44 | 45 | 46 | com.alibaba 47 | fastjson 48 | 1.2.12 49 | 50 | 51 | net.sf.flexjson 52 | flexjson 53 | 3.3 54 | 55 | 56 | com.google.code.gson 57 | gson 58 | 2.7 59 | 60 | 61 | com.owlike 62 | genson 63 | 1.4 64 | 65 | 66 | hr.ngs.benchmark 67 | generated-model 68 | 1.6 69 | 70 | 71 | com.esotericsoftware 72 | kryo 73 | 4.0.0 74 | 75 | 76 | de.javakaffee 77 | kryo-serializers 78 | 0.37 79 | 80 | 81 | de.ruedigermoeller 82 | fst 83 | 2.45 84 | 85 | 86 | 87 | 88 | UTF-8 89 | 90 | 91 | 92 | 93 | 94 | maven-compiler-plugin 95 | 3.5.1 96 | 97 | 1.8 98 | 1.8 99 | 100 | 101 | 102 | maven-assembly-plugin 103 | 2.6 104 | 105 | 106 | 107 | hr.ngs.benchmark.Main 108 | 109 | 110 | 111 | jar-with-dependencies 112 | 113 | 114 | 115 | 116 | make-assembly 117 | package 118 | 119 | single 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/FlatBuf/SmallObjects/Complex.java: -------------------------------------------------------------------------------- 1 | // automatically generated, do not modify 2 | 3 | package FlatBuf.SmallObjects; 4 | 5 | import java.nio.*; 6 | import java.lang.*; 7 | import java.util.*; 8 | import com.google.flatbuffers.*; 9 | 10 | public class Complex extends Table { 11 | public static Complex getRootAsComplex(ByteBuffer _bb) { return getRootAsComplex(_bb, new Complex()); } 12 | public static Complex getRootAsComplex(ByteBuffer _bb, Complex obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } 13 | public Complex __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } 14 | 15 | public String x() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } 16 | public ByteBuffer xAsByteBuffer() { return __vector_as_bytebuffer(4, 1); } 17 | public float y() { int o = __offset(6); return o != 0 ? bb.getFloat(o + bb_pos) : 0; } 18 | public long z() { int o = __offset(8); return o != 0 ? bb.getLong(o + bb_pos) : 0; } 19 | 20 | public static int createComplex(FlatBufferBuilder builder, 21 | int x, 22 | float y, 23 | long z) { 24 | builder.startObject(3); 25 | Complex.addZ(builder, z); 26 | Complex.addY(builder, y); 27 | Complex.addX(builder, x); 28 | return Complex.endComplex(builder); 29 | } 30 | 31 | public static void startComplex(FlatBufferBuilder builder) { builder.startObject(3); } 32 | public static void addX(FlatBufferBuilder builder, int xOffset) { builder.addOffset(0, xOffset, 0); } 33 | public static void addY(FlatBufferBuilder builder, float y) { builder.addFloat(1, y, 0); } 34 | public static void addZ(FlatBufferBuilder builder, long z) { builder.addLong(2, z, 0); } 35 | public static int endComplex(FlatBufferBuilder builder) { 36 | int o = builder.endObject(); 37 | return o; 38 | } 39 | public static void finishComplexBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset); } 40 | }; 41 | 42 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/FlatBuf/SmallObjects/Message.java: -------------------------------------------------------------------------------- 1 | // automatically generated, do not modify 2 | 3 | package FlatBuf.SmallObjects; 4 | 5 | import com.google.flatbuffers.FlatBufferBuilder; 6 | import com.google.flatbuffers.Table; 7 | 8 | import java.nio.ByteBuffer; 9 | import java.nio.ByteOrder; 10 | 11 | public class Message extends Table { 12 | public static FlatBuf.SmallObjects.Message getRootAsMessage(ByteBuffer _bb) { return getRootAsMessage(_bb, new FlatBuf.SmallObjects.Message()); } 13 | public static FlatBuf.SmallObjects.Message getRootAsMessage(ByteBuffer _bb, FlatBuf.SmallObjects.Message obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } 14 | public FlatBuf.SmallObjects.Message __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } 15 | 16 | public String message() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } 17 | public ByteBuffer messageAsByteBuffer() { return __vector_as_bytebuffer(4, 1); } 18 | public int version() { int o = __offset(6); return o != 0 ? bb.getInt(o + bb_pos) : 0; } 19 | 20 | public static int createMessage(FlatBufferBuilder builder, 21 | int message, 22 | int version) { 23 | builder.startObject(2); 24 | FlatBuf.SmallObjects.Message.addVersion(builder, version); 25 | FlatBuf.SmallObjects.Message.addMessage(builder, message); 26 | return FlatBuf.SmallObjects.Message.endMessage(builder); 27 | } 28 | 29 | public static void startMessage(FlatBufferBuilder builder) { builder.startObject(2); } 30 | public static void addMessage(FlatBufferBuilder builder, int messageOffset) { builder.addOffset(0, messageOffset, 0); } 31 | public static void addVersion(FlatBufferBuilder builder, int version) { builder.addInt(1, version, 0); } 32 | public static int endMessage(FlatBufferBuilder builder) { 33 | int o = builder.endObject(); 34 | return o; 35 | } 36 | public static void finishMessageBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset); } 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/FlatBuf/SmallObjects/Post.java: -------------------------------------------------------------------------------- 1 | // automatically generated, do not modify 2 | 3 | package FlatBuf.SmallObjects; 4 | 5 | import java.nio.*; 6 | import java.lang.*; 7 | import java.util.*; 8 | import com.google.flatbuffers.*; 9 | 10 | public class Post extends Table { 11 | public static Post getRootAsPost(ByteBuffer _bb) { return getRootAsPost(_bb, new Post()); } 12 | public static Post getRootAsPost(ByteBuffer _bb, Post obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } 13 | public Post __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } 14 | 15 | public String ID() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } 16 | public ByteBuffer IDAsByteBuffer() { return __vector_as_bytebuffer(4, 1); } 17 | public String title() { int o = __offset(6); return o != 0 ? __string(o + bb_pos) : null; } 18 | public ByteBuffer titleAsByteBuffer() { return __vector_as_bytebuffer(6, 1); } 19 | public boolean active() { int o = __offset(8); return o != 0 ? 0!=bb.get(o + bb_pos) : false; } 20 | public long created() { int o = __offset(10); return o != 0 ? bb.getLong(o + bb_pos) : 0; } 21 | 22 | public static int createPost(FlatBufferBuilder builder, 23 | int ID, 24 | int title, 25 | boolean active, 26 | long created) { 27 | builder.startObject(4); 28 | Post.addCreated(builder, created); 29 | Post.addTitle(builder, title); 30 | Post.addID(builder, ID); 31 | Post.addActive(builder, active); 32 | return Post.endPost(builder); 33 | } 34 | 35 | public static void startPost(FlatBufferBuilder builder) { builder.startObject(4); } 36 | public static void addID(FlatBufferBuilder builder, int IDOffset) { builder.addOffset(0, IDOffset, 0); } 37 | public static void addTitle(FlatBufferBuilder builder, int titleOffset) { builder.addOffset(1, titleOffset, 0); } 38 | public static void addActive(FlatBufferBuilder builder, boolean active) { builder.addBoolean(2, active, false); } 39 | public static void addCreated(FlatBufferBuilder builder, long created) { builder.addLong(3, created, 0); } 40 | public static int endPost(FlatBufferBuilder builder) { 41 | int o = builder.endObject(); 42 | return o; 43 | } 44 | public static void finishPostBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset); } 45 | }; 46 | 47 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/com/google/flatbuffers/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.flatbuffers; 18 | 19 | // Class that holds shared constants. 20 | 21 | public class Constants { 22 | // Java doesn't seem to have these. 23 | static final int SIZEOF_SHORT = 2; 24 | static final int SIZEOF_INT = 4; 25 | static final int FILE_IDENTIFIER_LENGTH = 4; 26 | } 27 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/com/google/flatbuffers/FlatBufferBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.flatbuffers; 18 | 19 | import static com.google.flatbuffers.Constants.*; 20 | import java.util.Arrays; 21 | import java.nio.ByteBuffer; 22 | import java.nio.ByteOrder; 23 | import java.nio.charset.Charset; 24 | 25 | /** 26 | * Class that helps you build a FlatBuffer. See the section 27 | * "Use in Java" in the 28 | * main FlatBuffers documentation. 29 | */ 30 | public class FlatBufferBuilder { 31 | ByteBuffer bb; // Where we construct the FlatBuffer. 32 | int space; // Remaining space in the ByteBuffer. 33 | static final Charset utf8charset = Charset.forName("UTF-8"); 34 | int minalign = 1; // Minimum alignment encountered so far. 35 | int[] vtable = null; // The vtable for the current table. 36 | int vtable_in_use = 0; // The amount of fields we're actually using. 37 | boolean nested = false; // Whether we are currently serializing a table. 38 | int object_start; // Starting offset of the current struct/table. 39 | int[] vtables = new int[16]; // List of offsets of all vtables. 40 | int num_vtables = 0; // Number of entries in `vtables` in use. 41 | int vector_num_elems = 0; // For the current vector being built. 42 | boolean force_defaults = false; // False omits default values from the serialized data 43 | 44 | /** 45 | * Start with a buffer of size {@code initial_size}, then grow as required. 46 | * 47 | * @param initial_size The initial size of the internal buffer to use 48 | */ 49 | public FlatBufferBuilder(int initial_size) { 50 | if (initial_size <= 0) initial_size = 1; 51 | space = initial_size; 52 | bb = newByteBuffer(initial_size); 53 | } 54 | 55 | /** 56 | * Start with a buffer of 1KiB, then grow as required. 57 | */ 58 | public FlatBufferBuilder() { 59 | this(1024); 60 | } 61 | 62 | /** 63 | * Alternative constructor allowing reuse of {@link ByteBuffer}s. The builder 64 | * can still grow the buffer as necessary. User classes should make sure 65 | * to call {@link #dataBuffer()} to obtain the resulting encoded message 66 | * 67 | * @param existing_bb The byte buffer to reuse 68 | */ 69 | public FlatBufferBuilder(ByteBuffer existing_bb) { 70 | init(existing_bb); 71 | } 72 | 73 | /** 74 | * Alternative initializer that allows reusing this object on an existing 75 | * ByteBuffer. This method resets the builder's internal state, but keeps 76 | * objects that have been allocated for temporary storage. 77 | * 78 | * @param existing_bb The byte buffer to reuse 79 | * @return this 80 | */ 81 | public FlatBufferBuilder init(ByteBuffer existing_bb){ 82 | bb = existing_bb; 83 | bb.clear(); 84 | bb.order(ByteOrder.LITTLE_ENDIAN); 85 | minalign = 1; 86 | space = bb.capacity(); 87 | vtable_in_use = 0; 88 | nested = false; 89 | object_start = 0; 90 | num_vtables = 0; 91 | vector_num_elems = 0; 92 | return this; 93 | } 94 | 95 | static ByteBuffer newByteBuffer(int capacity) { 96 | ByteBuffer newbb = ByteBuffer.allocate(capacity); 97 | newbb.order(ByteOrder.LITTLE_ENDIAN); 98 | return newbb; 99 | } 100 | 101 | /** 102 | * Doubles the size of the backing {link ByteBuffer} and copies the old data towards the 103 | * end of the new buffer (since we build the buffer backwards). 104 | * 105 | * @param bb The current buffer with the existing data 106 | * @return A new byte buffer with the old data copied copied to it. The data is 107 | * located at the end of the buffer. 108 | */ 109 | static ByteBuffer growByteBuffer(ByteBuffer bb) { 110 | int old_buf_size = bb.capacity(); 111 | if ((old_buf_size & 0xC0000000) != 0) // Ensure we don't grow beyond what fits in an int. 112 | throw new AssertionError("FlatBuffers: cannot grow buffer beyond 2 gigabytes."); 113 | int new_buf_size = old_buf_size << 1; 114 | bb.position(0); 115 | ByteBuffer nbb = newByteBuffer(new_buf_size); 116 | nbb.position(new_buf_size - old_buf_size); 117 | nbb.put(bb); 118 | return nbb; 119 | } 120 | 121 | /** 122 | * Offset relative to the end of the buffer. 123 | * 124 | * @return Offset relative to the end of the buffer. 125 | */ 126 | public int offset() { 127 | return bb.capacity() - space; 128 | } 129 | 130 | /** 131 | * Add zero valued bytes to prepare a new entry to be added 132 | * 133 | * @param byte_size Number of bytes to add. 134 | */ 135 | public void pad(int byte_size) { 136 | for (int i = 0; i < byte_size; i++) bb.put(--space, (byte)0); 137 | } 138 | 139 | /** 140 | * Prepare to write an element of {@code size} after {@code additional_bytes} 141 | * have been written, e.g. if you write a string, you need to align such 142 | * the int length field is aligned to {@link com.google.flatbuffers.Constants#SIZEOF_INT}, and 143 | * the string data follows it directly. If all you need to do is alignment, {@code additional_bytes} 144 | * will be 0. 145 | * 146 | * @param size This is the of the new element to write 147 | * @param additional_bytes The padding size 148 | */ 149 | public void prep(int size, int additional_bytes) { 150 | // Track the biggest thing we've ever aligned to. 151 | if (size > minalign) minalign = size; 152 | // Find the amount of alignment needed such that `size` is properly 153 | // aligned after `additional_bytes` 154 | int align_size = ((~(bb.capacity() - space + additional_bytes)) + 1) & (size - 1); 155 | // Reallocate the buffer if needed. 156 | while (space < align_size + size + additional_bytes) { 157 | int old_buf_size = bb.capacity(); 158 | bb = growByteBuffer(bb); 159 | space += bb.capacity() - old_buf_size; 160 | } 161 | pad(align_size); 162 | } 163 | 164 | // Add a scalar to the buffer, backwards from the current location. 165 | // Doesn't align nor check for space. 166 | public void putBoolean(boolean x) { bb.put (space -= 1, (byte)(x ? 1 : 0)); } 167 | public void putByte (byte x) { bb.put (space -= 1, x); } 168 | public void putShort (short x) { bb.putShort (space -= 2, x); } 169 | public void putInt (int x) { bb.putInt (space -= 4, x); } 170 | public void putLong (long x) { bb.putLong (space -= 8, x); } 171 | public void putFloat (float x) { bb.putFloat (space -= 4, x); } 172 | public void putDouble (double x) { bb.putDouble(space -= 8, x); } 173 | 174 | // Adds a scalar to the buffer, properly aligned, and the buffer grown 175 | // if needed. 176 | public void addBoolean(boolean x) { prep(1, 0); putBoolean(x); } 177 | public void addByte (byte x) { prep(1, 0); putByte (x); } 178 | public void addShort (short x) { prep(2, 0); putShort (x); } 179 | public void addInt (int x) { prep(4, 0); putInt (x); } 180 | public void addLong (long x) { prep(8, 0); putLong (x); } 181 | public void addFloat (float x) { prep(4, 0); putFloat (x); } 182 | public void addDouble (double x) { prep(8, 0); putDouble (x); } 183 | 184 | /** 185 | * Adds on offset, relative to where it will be written. 186 | * 187 | * @param off The offset to add 188 | */ 189 | public void addOffset(int off) { 190 | prep(SIZEOF_INT, 0); // Ensure alignment is already done. 191 | assert off <= offset(); 192 | off = offset() - off + SIZEOF_INT; 193 | putInt(off); 194 | } 195 | 196 | /** 197 | * Start a new array/vector of objects. Users usually will not call 198 | * this directly. The {@code FlatBuffers} compiler will create a start/end 199 | * method for vector types in generated code. 200 | *

201 | * The expected sequence of calls is: 202 | *

    203 | *
  1. Start the array using this method.
  2. 204 | *
  3. Call {@link #addOffset(int)} {@code num_elems} number of times to set 205 | * the offset of each element in the array.
  4. 206 | *
  5. Call {@link #endVector()} to retrieve the offset of the array.
  6. 207 | *
208 | *

209 | * For example, to create an array of strings, do: 210 | *

{@code
211 |     * // Need 10 strings
212 |     * FlatBufferBuilder builder = new FlatBufferBuilder(existingBuffer);
213 |     * int[] offsets = new int[10];
214 |     *
215 |     * for (int i = 0; i < 10; i++) {
216 |     *   offsets[i] = fbb.createString(" " + i);
217 |     * }
218 |     *
219 |     * // Have the strings in the buffer, but don't have a vector.
220 |     * // Add a vector that references the newly created strings:
221 |     * builder.startVector(4, offsets.length, 4);
222 |     *
223 |     * // Add each string to the newly created vector
224 |     * // The strings are added in reverse order since the buffer
225 |     * // is filled in back to front
226 |     * for (int i = offsets.length - 1; i >= 0; i--) {
227 |     *   builder.addOffset(offsets[i]);
228 |     * }
229 |     *
230 |     * // Finish off the vector
231 |     * int offsetOfTheVector = fbb.endVector();
232 |     * }
233 | * 234 | * @param elem_size The size of each element in the array 235 | * @param num_elems The number of elements in the array 236 | * @param alignment The alignment of the array 237 | */ 238 | public void startVector(int elem_size, int num_elems, int alignment) { 239 | notNested(); 240 | vector_num_elems = num_elems; 241 | prep(SIZEOF_INT, elem_size * num_elems); 242 | prep(alignment, elem_size * num_elems); // Just in case alignment > int. 243 | } 244 | 245 | /** 246 | * Finish off the creation of an array and all its elements. The array 247 | * must be created with {@link #startVector(int, int, int)}. 248 | * 249 | * @return The offset at which the newly created array starts. 250 | * @see #startVector(int, int, int) 251 | */ 252 | public int endVector() { 253 | putInt(vector_num_elems); 254 | return offset(); 255 | } 256 | 257 | /** 258 | * Encode the string {@code s} in the buffer using UTF-8. 259 | * 260 | * @param s The string to encode 261 | * @return The offset in the buffer where the encoded string starts 262 | */ 263 | public int createString(String s) { 264 | byte[] utf8 = s.getBytes(utf8charset); 265 | addByte((byte)0); 266 | startVector(1, utf8.length, 1); 267 | bb.position(space -= utf8.length); 268 | bb.put(utf8, 0, utf8.length); 269 | return endVector(); 270 | } 271 | 272 | /** 273 | * Encode the string {@code s} in the buffer using UTF-8. 274 | * 275 | * @param s An already encoded UTF-8 string 276 | * @return The offset in the buffer where the encoded string starts 277 | */ 278 | public int createString(ByteBuffer s) { 279 | int length = s.remaining(); 280 | addByte((byte)0); 281 | startVector(1, length, 1); 282 | bb.position(space -= length); 283 | bb.put(s); 284 | return endVector(); 285 | } 286 | 287 | /** 288 | * Should not be creating any other object, string or vector 289 | * while an object is being constructed 290 | */ 291 | public void notNested() { 292 | if (nested) 293 | throw new AssertionError("FlatBuffers: object serialization must not be nested."); 294 | } 295 | 296 | /** 297 | * Structures are always stored inline, they need to be created right 298 | * where they're used. You'll get this assertion failure if you 299 | * created it elsewhere. 300 | * 301 | * @param obj The offset of the created object 302 | */ 303 | public void Nested(int obj) { 304 | if (obj != offset()) 305 | throw new AssertionError("FlatBuffers: struct must be serialized inline."); 306 | } 307 | 308 | /** 309 | * Start encoding a new object in the buffer. Users will not usually need to 310 | * call this directly. The {@code FlatBuffers} compiler will generate helper methods 311 | * that call this method internally. 312 | *

313 | * For example, using the "Monster" code found on the 314 | * landing page. An 315 | * object of type {@code Monster} can be created using the following code: 316 | * 317 | *

{@code
318 |     * int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
319 |     *   fbb.createString("test1"),
320 |     *   fbb.createString("test2")
321 |     * });
322 |     *
323 |     * Monster.startMonster(fbb);
324 |     * Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
325 |     *   Color.Green, (short)5, (byte)6));
326 |     * Monster.addHp(fbb, (short)80);
327 |     * Monster.addName(fbb, str);
328 |     * Monster.addInventory(fbb, inv);
329 |     * Monster.addTestType(fbb, (byte)Any.Monster);
330 |     * Monster.addTest(fbb, mon2);
331 |     * Monster.addTest4(fbb, test4);
332 |     * Monster.addTestarrayofstring(fbb, testArrayOfString);
333 |     * int mon = Monster.endMonster(fbb);
334 |     * }
335 | *

336 | * Here: 337 | *

    338 | *
  • The call to {@code Monster#startMonster(FlatBufferBuilder)} will call this 339 | * method with the right number of fields set.
  • 340 | *
  • {@code Monster#endMonster(FlatBufferBuilder)} will ensure {@link #endObject()} is called.
  • 341 | *
342 | *

343 | * It's not recommended to call this method directly. If it's called manually, you must ensure 344 | * to audit all calls to it whenever fields are added or removed from your schema. This is 345 | * automatically done by the code generated by the {@code FlatBuffers} compiler. 346 | * 347 | * @param numfields The number of fields found in this object. 348 | */ 349 | public void startObject(int numfields) { 350 | notNested(); 351 | if (vtable == null || vtable.length < numfields) vtable = new int[numfields]; 352 | vtable_in_use = numfields; 353 | Arrays.fill(vtable, 0, vtable_in_use, 0); 354 | nested = true; 355 | object_start = offset(); 356 | } 357 | 358 | // Add a scalar to a table at `o` into its vtable, with value `x` and default `d` 359 | public void addBoolean(int o, boolean x, boolean d) { if(force_defaults || x != d) { addBoolean(x); slot(o); } } 360 | public void addByte (int o, byte x, int d) { if(force_defaults || x != d) { addByte (x); slot(o); } } 361 | public void addShort (int o, short x, int d) { if(force_defaults || x != d) { addShort (x); slot(o); } } 362 | public void addInt (int o, int x, int d) { if(force_defaults || x != d) { addInt (x); slot(o); } } 363 | public void addLong (int o, long x, long d) { if(force_defaults || x != d) { addLong (x); slot(o); } } 364 | public void addFloat (int o, float x, double d) { if(force_defaults || x != d) { addFloat (x); slot(o); } } 365 | public void addDouble (int o, double x, double d) { if(force_defaults || x != d) { addDouble (x); slot(o); } } 366 | public void addOffset (int o, int x, int d) { if(force_defaults || x != d) { addOffset (x); slot(o); } } 367 | 368 | // Structs are stored inline, so nothing additional is being added. `d` is always 0. 369 | public void addStruct(int voffset, int x, int d) { 370 | if(x != d) { 371 | Nested(x); 372 | slot(voffset); 373 | } 374 | } 375 | 376 | // Set the current vtable at `voffset` to the current location in the buffer. 377 | public void slot(int voffset) { 378 | vtable[voffset] = offset(); 379 | } 380 | 381 | /** 382 | * Finish off writing the object that is under construction. 383 | * 384 | * @return The offset to the object inside {@link #dataBuffer()} 385 | * @see #startObject(int) 386 | */ 387 | public int endObject() { 388 | if (vtable == null || !nested) 389 | throw new AssertionError("FlatBuffers: endObject called without startObject"); 390 | addInt(0); 391 | int vtableloc = offset(); 392 | // Write out the current vtable. 393 | for (int i = vtable_in_use - 1; i >= 0 ; i--) { 394 | // Offset relative to the start of the table. 395 | short off = (short)(vtable[i] != 0 ? vtableloc - vtable[i] : 0); 396 | addShort(off); 397 | } 398 | 399 | final int standard_fields = 2; // The fields below: 400 | addShort((short)(vtableloc - object_start)); 401 | addShort((short)((vtable_in_use + standard_fields) * SIZEOF_SHORT)); 402 | 403 | // Search for an existing vtable that matches the current one. 404 | int existing_vtable = 0; 405 | outer_loop: 406 | for (int i = 0; i < num_vtables; i++) { 407 | int vt1 = bb.capacity() - vtables[i]; 408 | int vt2 = space; 409 | short len = bb.getShort(vt1); 410 | if (len == bb.getShort(vt2)) { 411 | for (int j = SIZEOF_SHORT; j < len; j += SIZEOF_SHORT) { 412 | if (bb.getShort(vt1 + j) != bb.getShort(vt2 + j)) { 413 | continue outer_loop; 414 | } 415 | } 416 | existing_vtable = vtables[i]; 417 | break outer_loop; 418 | } 419 | } 420 | 421 | if (existing_vtable != 0) { 422 | // Found a match: 423 | // Remove the current vtable. 424 | space = bb.capacity() - vtableloc; 425 | // Point table to existing vtable. 426 | bb.putInt(space, existing_vtable - vtableloc); 427 | } else { 428 | // No match: 429 | // Add the location of the current vtable to the list of vtables. 430 | if (num_vtables == vtables.length) vtables = Arrays.copyOf(vtables, num_vtables * 2); 431 | vtables[num_vtables++] = offset(); 432 | // Point table to current vtable. 433 | bb.putInt(bb.capacity() - vtableloc, offset() - vtableloc); 434 | } 435 | 436 | nested = false; 437 | return vtableloc; 438 | } 439 | 440 | // This checks a required field has been set in a given table that has 441 | // just been constructed. 442 | public void required(int table, int field) { 443 | int table_start = bb.capacity() - table; 444 | int vtable_start = table_start - bb.getInt(table_start); 445 | boolean ok = bb.getShort(vtable_start + field) != 0; 446 | // If this fails, the caller will show what field needs to be set. 447 | if (!ok) 448 | throw new AssertionError("FlatBuffers: field " + field + " must be set"); 449 | } 450 | 451 | public void finish(int root_table) { 452 | prep(minalign, SIZEOF_INT); 453 | addOffset(root_table); 454 | bb.position(space); 455 | } 456 | 457 | public void finish(int root_table, String file_identifier) { 458 | prep(minalign, SIZEOF_INT + FILE_IDENTIFIER_LENGTH); 459 | if (file_identifier.length() != FILE_IDENTIFIER_LENGTH) 460 | throw new AssertionError("FlatBuffers: file identifier must be length " + 461 | FILE_IDENTIFIER_LENGTH); 462 | for (int i = FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) { 463 | addByte((byte)file_identifier.charAt(i)); 464 | } 465 | finish(root_table); 466 | } 467 | 468 | /** 469 | * In order to save space, fields that are set to their default value 470 | * don't get serialized into the buffer. Forcing defaults provides a 471 | * way to manually disable this optimization. 472 | * 473 | * @param forceDefaults true always serializes default values 474 | * @return this 475 | */ 476 | public FlatBufferBuilder forceDefaults(boolean forceDefaults){ 477 | this.force_defaults = forceDefaults; 478 | return this; 479 | } 480 | 481 | // Get the ByteBuffer representing the FlatBuffer. Only call this after you've 482 | // called finish(). The actual data starts at the ByteBuffer's current position, 483 | // not necessarily at 0. 484 | public ByteBuffer dataBuffer() { return bb; } 485 | 486 | /** 487 | * The FlatBuffer data doesn't start at offset 0 in the {@link ByteBuffer}, but 488 | * now the {@code ByteBuffer}'s position is set to that location upon {@link #finish(int)}. 489 | * 490 | * @return The {@link ByteBuffer#position() position} the data starts in {@link #dataBuffer()} 491 | * @deprecated This method should not be needed anymore, but is left 492 | * here for the moment to document this API change. It will be removed in the future. 493 | */ 494 | @Deprecated 495 | private int dataStart() { 496 | return space; 497 | } 498 | 499 | /** 500 | * Utility function for copying a byte array from {@code start} to 501 | * {@code start} + {@code length} 502 | * 503 | * @param start Start copying at this offset 504 | * @param length How many bytes to copy 505 | * @return A range copy of the {@link #dataBuffer() data buffer} 506 | * @throws IndexOutOfBoundsException If the range of bytes is ouf of bound 507 | */ 508 | public byte[] sizedByteArray(int start, int length){ 509 | byte[] array = new byte[length]; 510 | bb.position(start); 511 | bb.get(array); 512 | return array; 513 | } 514 | 515 | /** 516 | * Utility function for copying a byte array that starts at 0. 517 | * 518 | * @return A full copy of the {@link #dataBuffer() data buffer} 519 | */ 520 | public byte[] sizedByteArray() { 521 | return sizedByteArray(space, bb.capacity() - space); 522 | } 523 | } -------------------------------------------------------------------------------- /Benchmark/src/main/java/com/google/flatbuffers/Struct.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.flatbuffers; 18 | 19 | import java.nio.ByteBuffer; 20 | 21 | // All structs in the generated code derive from this class, and add their own accessors. 22 | public class Struct { 23 | protected int bb_pos; 24 | protected ByteBuffer bb; 25 | } -------------------------------------------------------------------------------- /Benchmark/src/main/java/com/google/flatbuffers/Table.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.flatbuffers; 18 | 19 | import static com.google.flatbuffers.Constants.*; 20 | import java.nio.ByteBuffer; 21 | import java.nio.ByteOrder; 22 | 23 | // All tables in the generated code derive from this class, and add their own accessors. 24 | public class Table { 25 | protected int bb_pos; 26 | protected ByteBuffer bb; 27 | 28 | public ByteBuffer getByteBuffer() { return bb; } 29 | 30 | // Look up a field in the vtable, return an offset into the object, or 0 if the field is not 31 | // present. 32 | protected int __offset(int vtable_offset) { 33 | int vtable = bb_pos - bb.getInt(bb_pos); 34 | return vtable_offset < bb.getShort(vtable) ? bb.getShort(vtable + vtable_offset) : 0; 35 | } 36 | 37 | // Retrieve the relative offset stored at "offset" 38 | protected int __indirect(int offset) { 39 | return offset + bb.getInt(offset); 40 | } 41 | 42 | // Create a java String from UTF-8 data stored inside the flatbuffer. 43 | // This allocates a new string and converts to wide chars upon each access, 44 | // which is not very efficient. Instead, each FlatBuffer string also comes with an 45 | // accessor based on __vector_as_bytebuffer below, which is much more efficient, 46 | // assuming your Java program can handle UTF-8 data directly. 47 | protected String __string(int offset) { 48 | offset += bb.getInt(offset); 49 | if (bb.hasArray()) { 50 | return new String(bb.array(), bb.arrayOffset() + offset + SIZEOF_INT, bb.getInt(offset), FlatBufferBuilder.utf8charset); 51 | } else { 52 | // We can't access .array(), since the ByteBuffer is read-only, 53 | // off-heap or a memory map 54 | ByteBuffer bb = this.bb.duplicate().order(ByteOrder.LITTLE_ENDIAN); 55 | // We're forced to make an extra copy: 56 | byte[] copy = new byte[bb.getInt(offset)]; 57 | bb.position(offset + SIZEOF_INT); 58 | bb.get(copy); 59 | return new String(copy, 0, copy.length, FlatBufferBuilder.utf8charset); 60 | } 61 | } 62 | 63 | // Get the length of a vector whose offset is stored at "offset" in this object. 64 | protected int __vector_len(int offset) { 65 | offset += bb_pos; 66 | offset += bb.getInt(offset); 67 | return bb.getInt(offset); 68 | } 69 | 70 | // Get the start of data of a vector whose offset is stored at "offset" in this object. 71 | protected int __vector(int offset) { 72 | offset += bb_pos; 73 | return offset + bb.getInt(offset) + SIZEOF_INT; // data starts after the length 74 | } 75 | 76 | // Get a whole vector as a ByteBuffer. This is efficient, since it only allocates a new 77 | // bytebuffer object, but does not actually copy the data, it still refers to the same 78 | // bytes as the original ByteBuffer. 79 | // Also useful with nested FlatBuffers etc. 80 | protected ByteBuffer __vector_as_bytebuffer(int vector_offset, int elem_size) { 81 | int o = __offset(vector_offset); 82 | if (o == 0) return null; 83 | ByteBuffer bb = this.bb.duplicate().order(ByteOrder.LITTLE_ENDIAN); 84 | int vectorstart = __vector(o); 85 | bb.position(vectorstart); 86 | bb.limit(vectorstart + __vector_len(o) * elem_size); 87 | return bb; 88 | } 89 | 90 | // Initialize any Table-derived type to point to the union at the given offset. 91 | protected Table __union(Table t, int offset) { 92 | offset += bb_pos; 93 | t.bb_pos = offset + bb.getInt(offset); 94 | t.bb = bb; 95 | return t; 96 | } 97 | 98 | protected static boolean __has_identifier(ByteBuffer bb, String ident) { 99 | if (ident.length() != FILE_IDENTIFIER_LENGTH) 100 | throw new AssertionError("FlatBuffers: file identifier must be length " + 101 | FILE_IDENTIFIER_LENGTH); 102 | for (int i = 0; i < FILE_IDENTIFIER_LENGTH; i++) { 103 | if (ident.charAt(i) != (char)bb.get(bb.position() + SIZEOF_INT + i)) return false; 104 | } 105 | return true; 106 | } 107 | } -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/Main.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark; 2 | 3 | import hr.ngs.benchmark.serializers.*; 4 | 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.IOException; 7 | import java.math.BigDecimal; 8 | import java.time.Clock; 9 | import java.time.LocalDate; 10 | import java.time.OffsetDateTime; 11 | import java.time.temporal.ChronoUnit; 12 | import java.util.*; 13 | 14 | public class Main { 15 | 16 | private enum BenchTarget { 17 | DslJsonFull, DslJsonMinimal, Jackson, JacksonAfterburner, 18 | Boon, Gson, Genson, Alibaba, Flexjson, 19 | Kryo, FST, 20 | FlatBuf 21 | } 22 | 23 | private enum BenchSize { 24 | Small, Standard, Large 25 | } 26 | 27 | private enum BenchType { 28 | Serialization, Both, None, Check 29 | } 30 | 31 | private static String EnumTypes(T[] enums) { 32 | StringBuilder sb = new StringBuilder(); 33 | sb.append(enums[0].name()); 34 | for (int i = 1; i < enums.length; i++) { 35 | sb.append(" | ").append(enums[i].name()); 36 | } 37 | return sb.toString(); 38 | } 39 | 40 | private static class ByteStream extends ByteArrayOutputStream { 41 | public byte[] getBytes() { 42 | return this.buf; 43 | } 44 | } 45 | 46 | public static void main(String[] args) throws Exception { 47 | //args = new String[]{"Genson", "Small", "Check", "100"}; 48 | if (args.length != 4) { 49 | System.out.printf( 50 | "Expected usage: java -jar json-benchamrk.jar (%s) (%s) (%s) n", 51 | EnumTypes(BenchTarget.values()), 52 | EnumTypes(BenchSize.values()), 53 | EnumTypes(BenchType.values())); 54 | System.exit(-1); 55 | return; 56 | } 57 | BenchTarget target; 58 | try { 59 | target = BenchTarget.valueOf(args[0]); 60 | } catch (Exception ex) { 61 | System.out.println("Unknown target found: " + args[0] + ". Supported targets: " + EnumTypes(BenchTarget.values())); 62 | System.exit(-2); 63 | return; 64 | } 65 | BenchSize size; 66 | try { 67 | size = BenchSize.valueOf(args[1]); 68 | } catch (Exception ex) { 69 | System.out.println("Unknown size found: " + args[1] + ". Supported targets: " + EnumTypes(BenchSize.values())); 70 | System.exit(-3); 71 | return; 72 | } 73 | BenchType type; 74 | try { 75 | type = BenchType.valueOf(args[2]); 76 | } catch (Exception ex) { 77 | System.out.println("Unknown type found: " + args[2] + ". Supported targets: " + EnumTypes(BenchType.values())); 78 | System.exit(-4); 79 | return; 80 | } 81 | int repeat; 82 | try { 83 | repeat = Integer.parseInt(args[3]); 84 | } catch (Exception ex) { 85 | System.out.println("Invalid repeat parameter: " + args[3]); 86 | System.exit(-5); 87 | return; 88 | } 89 | Serializer serializer; 90 | if (target == BenchTarget.Jackson) { 91 | serializer = new JacksonSerializer(false); 92 | } else if (target == BenchTarget.JacksonAfterburner) { 93 | serializer = new JacksonSerializer(true); 94 | } else if (target == BenchTarget.Alibaba) { 95 | serializer = new AlibabaSerializer(); 96 | } else if (target == BenchTarget.Boon) { 97 | serializer = new BoonSerializer(); 98 | } else if (target == BenchTarget.Flexjson) { 99 | serializer = new FlexJsonSerializer(); 100 | } else if (target == BenchTarget.Gson) { 101 | serializer = new GsonSerializer(); 102 | } else if (target == BenchTarget.Genson) { 103 | serializer = new GensonSerializer(); 104 | } else if (target == BenchTarget.Kryo) { 105 | serializer = new KryoSerializer(); 106 | } else if (target == BenchTarget.FST) { 107 | serializer = new FstSerializer(); 108 | } else if (target == BenchTarget.FlatBuf) { 109 | serializer = new FlatBufSerializer(); 110 | } else if (target == BenchTarget.DslJsonFull) { 111 | serializer = new DslJsonSerializer(false); 112 | } else if (target == BenchTarget.DslJsonMinimal) { 113 | serializer = new DslJsonSerializer(true); 114 | } else { 115 | System.out.println("Unmapped target ;("); 116 | System.exit(-99); 117 | return; 118 | } 119 | try { 120 | if (size == BenchSize.Small) { 121 | testSmall(repeat, serializer, type); 122 | } else if (size == BenchSize.Standard) { 123 | testStandard(repeat, serializer, type); 124 | } else { 125 | testLarge(repeat, serializer, type); 126 | } 127 | } catch (Exception ex) { 128 | reportError(ex); 129 | } 130 | } 131 | 132 | private static void reportStats(long start, long result, int incorrect) { 133 | long stop = System.nanoTime(); 134 | long timediff = (stop - start) / 1000000; 135 | System.out.println("duration = " + timediff); 136 | System.out.println("size = " + result); 137 | System.out.println("invalid deserialization = " + incorrect); 138 | } 139 | 140 | private static void reportError(Exception ex) { 141 | System.out.println("duration = -1"); 142 | System.out.println("size = -1"); 143 | System.out.println("invalid deserialization = -1"); 144 | System.out.println("duration = -1"); 145 | System.out.println("size = -1"); 146 | System.out.println("invalid deserialization = -1"); 147 | System.out.println("duration = -1"); 148 | System.out.println("size = -1"); 149 | System.out.println("invalid deserialization = -1"); 150 | System.out.println("error"); 151 | //ex.printStackTrace(); ///.NET Process.WaitForExit doesn't work with such stacktrace error 152 | System.out.println(ex.getMessage()); 153 | System.exit(-42); 154 | } 155 | 156 | private static void testSmall(int repeat, Serializer serializer, BenchType type) throws IOException { 157 | int incorrect = 0; 158 | ByteStream stream = new ByteStream(); 159 | long start = System.nanoTime(); 160 | long size = 0; 161 | for (int i = 0; i < repeat; i++) { 162 | hr.ngs.benchmark.SmallObjects.Message message = new hr.ngs.benchmark.SmallObjects.Message(); 163 | message.setMessage("some message " + i); 164 | message.setVersion(i); 165 | if (type == BenchType.None) continue; 166 | stream.reset(); 167 | serializer.serialize(message, stream); 168 | size += stream.size(); 169 | if (type == BenchType.Both || type == BenchType.Check) { 170 | hr.ngs.benchmark.SmallObjects.Message deser = serializer.deserialize(hr.ngs.benchmark.SmallObjects.Message.class, stream.getBytes(), stream.size()); 171 | if (type == BenchType.Check && !message.equals(deser)) { 172 | incorrect++; 173 | //throw new IOException("not equal"); 174 | } 175 | } 176 | } 177 | reportStats(start, size, incorrect); 178 | size = 0; 179 | start = System.nanoTime(); 180 | incorrect = 0; 181 | for (int i = 0; i < repeat; i++) { 182 | hr.ngs.benchmark.SmallObjects.Complex complex = new hr.ngs.benchmark.SmallObjects.Complex(); 183 | complex.setX(BigDecimal.valueOf(i / 1000d)); 184 | complex.setY(-i / 1000f); 185 | complex.setZ(i); 186 | if (type == BenchType.None) continue; 187 | stream.reset(); 188 | serializer.serialize(complex, stream); 189 | size += stream.size(); 190 | if (type == BenchType.Both || type == BenchType.Check) { 191 | hr.ngs.benchmark.SmallObjects.Complex deser = serializer.deserialize(hr.ngs.benchmark.SmallObjects.Complex.class, stream.getBytes(), stream.size()); 192 | if (type == BenchType.Check && !deser.equals(complex)) { 193 | incorrect++; 194 | //throw new SerializationException("not equal"); 195 | } 196 | } 197 | } 198 | reportStats(start, size, incorrect); 199 | size = 0; 200 | OffsetDateTime now = OffsetDateTime.now(Clock.systemUTC()); 201 | String ld = now.toLocalDate().toString(); 202 | start = System.nanoTime(); 203 | incorrect = 0; 204 | for (int i = 0; i < repeat; i++) { 205 | hr.ngs.benchmark.SmallObjects.Post post = new hr.ngs.benchmark.SmallObjects.Post(); 206 | post.setID(UUID.randomUUID()); 207 | post.setTitle("some title " + i); 208 | post.setActive(i % 2 == 0); 209 | post.setCreated(now.plusMinutes(i).toLocalDate()); 210 | if (type == BenchType.None) continue; 211 | stream.reset(); 212 | serializer.serialize(post, stream); 213 | size += stream.size(); 214 | if (type == BenchType.Both || type == BenchType.Check) { 215 | hr.ngs.benchmark.SmallObjects.Post deser = serializer.deserialize(hr.ngs.benchmark.SmallObjects.Post.class, stream.getBytes(), stream.size()); 216 | if (type == BenchType.Check && !deser.equals(post)) { 217 | incorrect++; 218 | //throw new SerializationException("not equal"); 219 | } 220 | } 221 | } 222 | reportStats(start, size, incorrect); 223 | } 224 | 225 | private static void testStandard(int repeat, Serializer serializer, BenchType type) throws IOException { 226 | int incorrect = 0; 227 | ByteStream stream = new ByteStream(); 228 | OffsetDateTime now = OffsetDateTime.now(Clock.systemUTC()); 229 | LocalDate today = LocalDate.now(); 230 | UUID[] uuids = new UUID[100]; 231 | for (int i = 0; i < 100; i++) { 232 | uuids[i] = UUID.randomUUID(); 233 | } 234 | String[][] tags = new String[][]{new String[0], new String[]{"JSON"}, new String[]{".NET", "Java", "benchmark"}}; 235 | long size = 0; 236 | hr.ngs.benchmark.StandardObjects.PostState[] states = hr.ngs.benchmark.StandardObjects.PostState.values(); 237 | long start = System.nanoTime(); 238 | for (int i = 0; i < repeat; i++) { 239 | hr.ngs.benchmark.StandardObjects.DeletePost delete = new hr.ngs.benchmark.StandardObjects.DeletePost(); 240 | delete.setPostID(i); 241 | delete.setDeletedBy(i / 100); 242 | delete.setLastModified(now.plusSeconds(i)); 243 | delete.setReason("no reason"); 244 | if (i % 3 == 0) delete.setReferenceId(uuids[i % 100]); 245 | if (i % 5 == 0) delete.setState(states[i % 3]); 246 | if (i % 7 == 0) { 247 | delete.setVersions(new long[i % 100 + 1]); 248 | for (int x = 0; x <= i % 100; x++) 249 | delete.getVersions()[x] = i * x + x; 250 | } 251 | if (i % 2 == 0 && i % 10 != 0) { 252 | delete.setVotes(new ArrayList<>()); 253 | for (int j = 0; j < i % 10; j++) { 254 | delete.getVotes().add((i + j) % 3 == 0 ? Boolean.TRUE : j % 2 == 0 ? Boolean.FALSE : null); 255 | } 256 | } 257 | if (type == BenchType.None) continue; 258 | stream.reset(); 259 | serializer.serialize(delete, stream); 260 | size += stream.size(); 261 | if (type == BenchType.Both || type == BenchType.Check) { 262 | hr.ngs.benchmark.StandardObjects.DeletePost deser = serializer.deserialize(hr.ngs.benchmark.StandardObjects.DeletePost.class, stream.getBytes(), stream.size()); 263 | if (type == BenchType.Check && !delete.equals(deser)) { 264 | incorrect++; 265 | //throw new SerializationException("not equal"); 266 | } 267 | } 268 | } 269 | reportStats(start, size, incorrect); 270 | size = 0; 271 | start = System.nanoTime(); 272 | incorrect = 0; 273 | for (int i = 0; i < repeat; i++) { 274 | hr.ngs.benchmark.StandardObjects.Post post = new hr.ngs.benchmark.StandardObjects.Post(); 275 | post.setID(-i); 276 | post.setApproved(i % 2 == 0 ? null : now.plus(i, ChronoUnit.MILLIS)); 277 | post.setVotes(new hr.ngs.benchmark.StandardObjects.Vote(i / 2, i / 3)); 278 | post.setText("some text describing post " + i); 279 | post.setTitle("post title " + i); 280 | post.setState(states[i % 3]); 281 | String[] t = tags[i % 3]; 282 | for (String aT : t) { 283 | post.getTags().add(aT); 284 | } 285 | post.setCreated(today.plusDays(i)); 286 | for (int j = 0; j < i % 100; j++) { 287 | hr.ngs.benchmark.StandardObjects.Comment comment = new hr.ngs.benchmark.StandardObjects.Comment(); 288 | comment.setCreated(today.plusDays(i + j)); 289 | comment.setMessage("comment number " + i + " for " + j); 290 | comment.setVotes(new hr.ngs.benchmark.StandardObjects.Vote(j, j * 2)); 291 | comment.setApproved(j % 3 != 0 ? null : now.plus(i, ChronoUnit.MILLIS)); 292 | comment.setUser("some random user " + i); 293 | post.getComments().add(comment); 294 | } 295 | if (type == BenchType.None) continue; 296 | stream.reset(); 297 | serializer.serialize(post, stream); 298 | size += stream.size(); 299 | if (type == BenchType.Both || type == BenchType.Check) { 300 | hr.ngs.benchmark.StandardObjects.Post deser = serializer.deserialize(hr.ngs.benchmark.StandardObjects.Post.class, stream.getBytes(), stream.size()); 301 | if (type == BenchType.Check && !post.equals(deser)) { 302 | incorrect++; 303 | //throw new SerializationException("not equal"); 304 | } 305 | } 306 | } 307 | reportStats(start, size, incorrect); 308 | } 309 | 310 | private static void testLarge(int repeat, Serializer serializer, BenchType type) throws IOException { 311 | int incorrect = 0; 312 | OffsetDateTime now = OffsetDateTime.now(Clock.systemUTC()); 313 | long size = 0; 314 | hr.ngs.benchmark.LargeObjects.Genre[] genresEnum = hr.ngs.benchmark.LargeObjects.Genre.values(); 315 | ByteStream stream = new ByteStream(); 316 | ArrayList illustrations = new ArrayList<>(); 317 | Random rnd = new Random(1); 318 | for (int i = 0; i < 10; i++) { 319 | byte[] buf = new byte[256 * i * i * i]; 320 | rnd.nextBytes(buf); 321 | illustrations.add(buf); 322 | } 323 | long start = System.nanoTime(); 324 | for (int i = 0; i < repeat; i++) { 325 | hr.ngs.benchmark.LargeObjects.Book book = new hr.ngs.benchmark.LargeObjects.Book(); 326 | book.setID(-i); 327 | book.setAuthorId(i / 100); 328 | book.setPublished(i % 3 == 0 ? null : now.plusMinutes(i).toLocalDate()); 329 | book.setTitle("book title " + i); 330 | hr.ngs.benchmark.LargeObjects.Genre[] genres = new hr.ngs.benchmark.LargeObjects.Genre[i % 2]; 331 | for (int j = 0; j < i % 2; j++) 332 | genres[j] = genresEnum[(i + j) % 4]; 333 | book.setGenres(genres); 334 | for (int j = 0; j < i % 20; j++) 335 | book.getChanges().add(now.plusMinutes(i).toLocalDate()); 336 | for (int j = 0; j < i % 50; j++) 337 | book.getMetadata().put("key " + i + j, "value " + i + j); 338 | if (i % 3 == 0 || i % 7 == 0) book.setCover(illustrations.get(i % illustrations.size())); 339 | StringBuilder sb = new StringBuilder(); 340 | for (int j = 0; j < i % 1000; j++) { 341 | sb.append("some text on page ").append(j); 342 | sb.append("more text for ").append(i); 343 | hr.ngs.benchmark.LargeObjects.Page page = new hr.ngs.benchmark.LargeObjects.Page(); 344 | page.setText(sb.toString()); 345 | for (int z = 0; z < i % 100; z++) { 346 | hr.ngs.benchmark.LargeObjects.Note note; 347 | if (z % 3 == 0) { 348 | hr.ngs.benchmark.LargeObjects.Headnote hn = new hr.ngs.benchmark.LargeObjects.Headnote(); 349 | hn.setModifiedAt(now.plusSeconds(i)); 350 | hn.setNote("headnote " + j + " at " + z); 351 | note = hn; 352 | } else { 353 | hr.ngs.benchmark.LargeObjects.Footnote fn = new hr.ngs.benchmark.LargeObjects.Footnote(); 354 | fn.setCreateadAt(now.plusSeconds(i)); 355 | fn.setNote("footnote " + j + " at " + z); 356 | fn.setIndex(i); 357 | note = fn; 358 | } 359 | if (z % 3 == 0) 360 | note.setWrittenBy("author " + j + " " + z); 361 | page.getNotes().add(note); 362 | } 363 | book.getPages().addLast(page); 364 | } 365 | if (type == BenchType.None) continue; 366 | stream.reset(); 367 | serializer.serialize(book, stream); 368 | size += stream.size(); 369 | if (type == BenchType.Both || type == BenchType.Check) { 370 | hr.ngs.benchmark.LargeObjects.Book deser = serializer.deserialize(hr.ngs.benchmark.LargeObjects.Book.class, stream.getBytes(), stream.size()); 371 | if (type == BenchType.Check && !book.equals(deser)) { 372 | incorrect++; 373 | //throw new SerializationException("not equal"); 374 | } 375 | } 376 | } 377 | reportStats(start, size, incorrect); 378 | } 379 | } 380 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/Serializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | public interface Serializer { 7 | void serialize(com.dslplatform.json.JsonObject arg, OutputStream stream) throws IOException; 8 | 9 | T deserialize(Class manifest, byte[] bytes, int len) throws IOException; 10 | } -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/serializers/AlibabaSerializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark.serializers; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.parser.*; 5 | import com.alibaba.fastjson.serializer.*; 6 | import com.dslplatform.json.JsonObject; 7 | import hr.ngs.benchmark.Serializer; 8 | 9 | import java.io.IOException; 10 | import java.io.OutputStream; 11 | import java.nio.charset.Charset; 12 | 13 | public class AlibabaSerializer implements Serializer { 14 | private final static Charset UTF8 = Charset.forName("UTF-8"); 15 | 16 | @Override 17 | public void serialize(JsonObject arg, OutputStream os) throws IOException { 18 | JSON.writeJSONString(os, UTF8, arg, SerializerFeature.WriteEnumUsingToString, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.UseISO8601DateFormat); 19 | } 20 | 21 | @Override 22 | public T deserialize(Class manifest, byte[] bytes, int length) throws IOException { 23 | return JSON.parseObject(bytes, 0, length, UTF8, manifest, Feature.DisableCircularReferenceDetect, Feature.AllowISO8601DateFormat); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/serializers/BoonSerializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark.serializers; 2 | 3 | import com.dslplatform.json.JsonObject; 4 | import hr.ngs.benchmark.Serializer; 5 | import io.advantageous.boon.json.*; 6 | import io.advantageous.boon.json.serializers.CustomObjectSerializer; 7 | import io.advantageous.boon.json.serializers.JsonSerializerInternal; 8 | import io.advantageous.boon.primitive.CharBuf; 9 | 10 | import java.io.IOException; 11 | import java.io.OutputStream; 12 | import java.io.OutputStreamWriter; 13 | import java.nio.charset.Charset; 14 | import java.time.LocalDate; 15 | import java.time.OffsetDateTime; 16 | 17 | public class BoonSerializer implements Serializer { 18 | private final static Charset UTF8 = Charset.forName("UTF-8"); 19 | 20 | private static class BoonLocalDateSerializer implements CustomObjectSerializer { 21 | @Override 22 | public Class type() { 23 | return LocalDate.class; 24 | } 25 | 26 | @Override 27 | public void serializeObject(JsonSerializerInternal jsonSerializerInternal, Object o, CharBuf charBuf) { 28 | charBuf.write(o.toString()); 29 | } 30 | } 31 | 32 | private static class BoonDateTimeSerializer implements CustomObjectSerializer { 33 | @Override 34 | public Class type() { 35 | return OffsetDateTime.class; 36 | } 37 | 38 | @Override 39 | public void serializeObject(JsonSerializerInternal jsonSerializerInternal, Object o, CharBuf charBuf) { 40 | charBuf.write(o.toString()); 41 | } 42 | } 43 | 44 | private final JsonSerializer serializer = new JsonSerializerFactory() 45 | .addTypeSerializer(LocalDate.class, new BoonLocalDateSerializer()) 46 | .addTypeSerializer(OffsetDateTime.class, new BoonDateTimeSerializer()) 47 | .create(); 48 | private final ObjectMapper mapper = JsonFactory.create(); 49 | private final CharBuf cb = CharBuf.createCharBuf(); 50 | 51 | @Override 52 | public void serialize(JsonObject arg, OutputStream os) throws IOException { 53 | serializer.serialize(cb, arg); 54 | cb.flush(); 55 | String json = cb.toStringAndRecycle(); 56 | OutputStreamWriter osw = new OutputStreamWriter(os, UTF8); 57 | osw.write(json); 58 | osw.flush(); 59 | } 60 | 61 | @Override 62 | public T deserialize(Class manifest, byte[] bytes, int length) throws IOException { 63 | return mapper.readValue(new String(bytes, 0, length, UTF8), manifest); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/serializers/DslJsonSerializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark.serializers; 2 | 3 | import com.dslplatform.json.DslJson; 4 | import com.dslplatform.json.JsonObject; 5 | import com.dslplatform.json.JsonWriter; 6 | import hr.ngs.benchmark.Serializer; 7 | 8 | import java.io.IOException; 9 | import java.io.OutputStream; 10 | 11 | public class DslJsonSerializer implements Serializer { 12 | private final DslJson json = new DslJson(); 13 | private final JsonWriter sw = new JsonWriter(); 14 | private final boolean minimal; 15 | 16 | public DslJsonSerializer(boolean minimal) { 17 | this.minimal = minimal; 18 | } 19 | 20 | @Override 21 | public void serialize(JsonObject arg, OutputStream os) throws IOException { 22 | arg.serialize(sw, minimal); 23 | sw.toStream(os); 24 | sw.reset(); 25 | } 26 | 27 | @Override 28 | public T deserialize(Class manifest, byte[] bytes, int length) throws IOException { 29 | return json.deserialize(manifest, bytes, length); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/serializers/FlatBufSerializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark.serializers; 2 | 3 | import com.dslplatform.json.JsonObject; 4 | import com.google.flatbuffers.FlatBufferBuilder; 5 | import hr.ngs.benchmark.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.io.OutputStream; 9 | import java.math.BigDecimal; 10 | import java.nio.ByteBuffer; 11 | import java.time.LocalDate; 12 | import java.util.UUID; 13 | 14 | public class FlatBufSerializer implements Serializer { 15 | private final FlatBufferBuilder fbb = new FlatBufferBuilder(); 16 | 17 | @Override 18 | public void serialize(JsonObject arg, OutputStream os) throws IOException { 19 | if (arg instanceof hr.ngs.benchmark.SmallObjects.Message) { 20 | hr.ngs.benchmark.SmallObjects.Message msg = (hr.ngs.benchmark.SmallObjects.Message) arg; 21 | int offset = FlatBuf.SmallObjects.Message.createMessage( 22 | fbb, 23 | fbb.createString(msg.getMessage()), 24 | msg.getVersion()); 25 | FlatBuf.SmallObjects.Message.finishMessageBuffer(fbb, offset); 26 | } else if (arg instanceof hr.ngs.benchmark.SmallObjects.Complex) { 27 | hr.ngs.benchmark.SmallObjects.Complex c = (hr.ngs.benchmark.SmallObjects.Complex) arg; 28 | int offset = FlatBuf.SmallObjects.Complex.createComplex( 29 | fbb, 30 | fbb.createString(c.getX().toString()), 31 | c.getY(), 32 | c.getZ()); 33 | FlatBuf.SmallObjects.Complex.finishComplexBuffer(fbb, offset); 34 | } else if (arg instanceof hr.ngs.benchmark.SmallObjects.Post) { 35 | hr.ngs.benchmark.SmallObjects.Post post = (hr.ngs.benchmark.SmallObjects.Post) arg; 36 | int offset = FlatBuf.SmallObjects.Post.createPost( 37 | fbb, 38 | fbb.createString(post.getID().toString()), 39 | fbb.createString(post.getTitle()), 40 | post.getActive(), 41 | post.getCreated().toEpochDay()); 42 | FlatBuf.SmallObjects.Post.finishPostBuffer(fbb, offset); 43 | } else { 44 | throw new IOException("Unknown target"); 45 | } 46 | ByteBuffer bb = fbb.dataBuffer(); 47 | os.write(bb.array(), bb.position(), bb.capacity() - bb.position()); 48 | //TODO: no reset :D 49 | fbb.init(fbb.dataBuffer()); 50 | } 51 | 52 | @Override 53 | public T deserialize(Class manifest, byte[] bytes, int length) throws IOException { 54 | ByteBuffer bb = ByteBuffer.wrap(bytes, 0, length); 55 | if (manifest.equals(hr.ngs.benchmark.SmallObjects.Message.class)) { 56 | FlatBuf.SmallObjects.Message message = FlatBuf.SmallObjects.Message.getRootAsMessage(bb); 57 | return (T) new hr.ngs.benchmark.SmallObjects.Message( 58 | message.message(), 59 | message.version()); 60 | } else if (manifest.equals(hr.ngs.benchmark.SmallObjects.Complex.class)) { 61 | FlatBuf.SmallObjects.Complex c = FlatBuf.SmallObjects.Complex.getRootAsComplex(bb); 62 | return (T) new hr.ngs.benchmark.SmallObjects.Complex( 63 | new BigDecimal(c.x()), 64 | c.y(), 65 | c.z()); 66 | } else if (manifest.equals(hr.ngs.benchmark.SmallObjects.Post.class)) { 67 | FlatBuf.SmallObjects.Post post = FlatBuf.SmallObjects.Post.getRootAsPost(bb); 68 | return (T) new hr.ngs.benchmark.SmallObjects.Post( 69 | UUID.fromString(post.ID()), 70 | post.title(), 71 | post.active(), 72 | LocalDate.ofEpochDay(post.created())); 73 | } 74 | return null; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/serializers/FlexJsonSerializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark.serializers; 2 | 3 | import com.dslplatform.json.JsonObject; 4 | import flexjson.JSONDeserializer; 5 | import flexjson.JSONSerializer; 6 | import flexjson.transformer.AbstractTransformer; 7 | import hr.ngs.benchmark.Serializer; 8 | 9 | import java.io.IOException; 10 | import java.io.OutputStream; 11 | import java.nio.charset.Charset; 12 | import java.time.LocalDate; 13 | import java.time.OffsetDateTime; 14 | import java.util.UUID; 15 | 16 | public class FlexJsonSerializer implements Serializer { 17 | private static final AbstractTransformer IDENTITY = new AbstractTransformer() { 18 | @Override 19 | public void transform(Object o) { 20 | getContext().writeQuoted(o.toString()); 21 | } 22 | }; 23 | private final JSONSerializer serializer = 24 | new JSONSerializer() 25 | .transform(IDENTITY, UUID.class) 26 | .transform(IDENTITY, LocalDate.class) 27 | .transform(IDENTITY, OffsetDateTime.class); 28 | private final JSONDeserializer deserializer = 29 | new JSONDeserializer<>() 30 | .use(UUID.class, (objectBinder, o, type, aClass) -> UUID.fromString((String) o)) 31 | .use(LocalDate.class, (objectBinder, o, type, aClass) -> LocalDate.parse((String) o)) 32 | .use(OffsetDateTime.class, (objectBinder, o, type, aClass) -> OffsetDateTime.parse((String) o)); 33 | private final static Charset UTF8 = Charset.forName("UTF-8"); 34 | 35 | @Override 36 | public void serialize(JsonObject arg, OutputStream os) throws IOException { 37 | os.write(serializer.serialize(arg).getBytes(UTF8)); 38 | } 39 | 40 | @Override 41 | public T deserialize(Class manifest, byte[] bytes, int length) throws IOException { 42 | return (T) deserializer.deserialize(new String(bytes, 0, length, UTF8), manifest); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/serializers/FstSerializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark.serializers; 2 | 3 | import com.dslplatform.json.JsonObject; 4 | import hr.ngs.benchmark.Serializer; 5 | import org.nustaq.serialization.FSTConfiguration; 6 | import org.nustaq.serialization.FSTObjectInput; 7 | import org.nustaq.serialization.FSTObjectOutput; 8 | 9 | import java.io.IOException; 10 | import java.io.OutputStream; 11 | 12 | public class FstSerializer implements Serializer { 13 | private final FSTConfiguration conf; 14 | private final FSTObjectInput objectInput; 15 | private final FSTObjectOutput objectOutput; 16 | 17 | public FstSerializer() { 18 | conf = FSTConfiguration.createDefaultConfiguration(); 19 | conf.setShareReferences(false); 20 | objectInput = new FSTObjectInput(conf); 21 | objectOutput = new FSTObjectOutput(conf); 22 | } 23 | 24 | @Override 25 | public void serialize(JsonObject arg, OutputStream os) throws IOException { 26 | objectOutput.resetForReUse(); 27 | objectOutput.writeObject(arg, arg.getClass()); 28 | os.write(objectOutput.getBuffer(), 0, objectOutput.getWritten()); 29 | } 30 | 31 | @Override 32 | public T deserialize(Class manifest, byte[] bytes, int length) throws IOException { 33 | objectInput.resetForReuseUseArray(bytes, length); 34 | try { 35 | return (T) objectInput.readObject(manifest); 36 | } catch (Exception e) { 37 | throw new IOException(e); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/serializers/GensonSerializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark.serializers; 2 | 3 | import com.dslplatform.json.JsonObject; 4 | import com.owlike.genson.Genson; 5 | import com.owlike.genson.GensonBuilder; 6 | import hr.ngs.benchmark.Serializer; 7 | 8 | import java.io.IOException; 9 | import java.io.OutputStream; 10 | import java.nio.charset.Charset; 11 | 12 | public class GensonSerializer implements Serializer { 13 | private final Genson genson = new GensonBuilder() 14 | .useDateAsTimestamp(false) 15 | .create(); 16 | private final static Charset UTF8 = Charset.forName("UTF-8"); 17 | 18 | @Override 19 | public void serialize(JsonObject arg, OutputStream os) throws IOException { 20 | genson.serialize(arg, os); 21 | } 22 | 23 | @Override 24 | public T deserialize(Class manifest, byte[] bytes, int length) throws IOException { 25 | return genson.deserialize(new String(bytes, 0, length, UTF8), manifest); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/serializers/GsonSerializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark.serializers; 2 | 3 | import com.google.gson.*; 4 | import hr.ngs.benchmark.Serializer; 5 | 6 | import java.io.IOException; 7 | import java.io.OutputStream; 8 | import java.io.OutputStreamWriter; 9 | import java.lang.reflect.Type; 10 | import java.nio.charset.Charset; 11 | import java.time.LocalDate; 12 | import java.time.OffsetDateTime; 13 | 14 | public class GsonSerializer implements Serializer { 15 | private final static Charset UTF8 = Charset.forName("UTF-8"); 16 | 17 | private static class GsonDateTimeTypeConverter implements JsonSerializer, JsonDeserializer { 18 | @Override 19 | public JsonElement serialize(OffsetDateTime src, Type srcType, JsonSerializationContext context) { 20 | return new JsonPrimitive(src.toString()); 21 | } 22 | 23 | @Override 24 | public OffsetDateTime deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { 25 | return OffsetDateTime.parse(json.getAsString()); 26 | } 27 | } 28 | 29 | private static class GsonLocalDateTypeConverter implements JsonSerializer, JsonDeserializer { 30 | @Override 31 | public JsonElement serialize(LocalDate src, Type srcType, JsonSerializationContext context) { 32 | return new JsonPrimitive(src.toString()); 33 | } 34 | 35 | @Override 36 | public LocalDate deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { 37 | return LocalDate.parse(json.getAsString()); 38 | } 39 | } 40 | 41 | private final Gson gson; 42 | 43 | public GsonSerializer() { 44 | GsonBuilder builder = new GsonBuilder(); 45 | builder.registerTypeAdapter(OffsetDateTime.class, new GsonDateTimeTypeConverter()); 46 | builder.registerTypeAdapter(LocalDate.class, new GsonLocalDateTypeConverter()); 47 | gson = builder.create(); 48 | } 49 | 50 | @Override 51 | public void serialize(com.dslplatform.json.JsonObject arg, OutputStream os) throws IOException { 52 | OutputStreamWriter osw = new OutputStreamWriter(os, UTF8); 53 | gson.toJson(arg, osw); 54 | osw.flush(); 55 | } 56 | 57 | @Override 58 | public T deserialize(Class manifest, byte[] bytes, int length) throws IOException { 59 | return gson.fromJson(new String(bytes, 0, length, UTF8), manifest); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/serializers/JacksonSerializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark.serializers; 2 | 3 | import com.dslplatform.json.JsonObject; 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import com.fasterxml.jackson.core.JsonParser; 6 | import com.fasterxml.jackson.databind.*; 7 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 8 | import com.fasterxml.jackson.module.afterburner.AfterburnerModule; 9 | import hr.ngs.benchmark.Serializer; 10 | 11 | import java.io.IOException; 12 | import java.io.OutputStream; 13 | 14 | public class JacksonSerializer implements Serializer { 15 | 16 | private final ObjectMapper mapper = new ObjectMapper() 17 | .registerModule(new JavaTimeModule()) 18 | .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) 19 | .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 20 | .configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true) 21 | .setSerializationInclusion(JsonInclude.Include.NON_NULL) 22 | .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); 23 | 24 | public JacksonSerializer(boolean withAfterburner) { 25 | if (withAfterburner) { 26 | mapper.registerModule(new AfterburnerModule()); 27 | } 28 | } 29 | 30 | @Override 31 | public void serialize(JsonObject arg, OutputStream os) throws IOException { 32 | mapper.writeValue(os, arg); 33 | } 34 | 35 | @Override 36 | public T deserialize(Class manifest, byte[] bytes, int length) throws IOException { 37 | return mapper.readValue(bytes, 0, length, manifest); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Benchmark/src/main/java/hr/ngs/benchmark/serializers/KryoSerializer.java: -------------------------------------------------------------------------------- 1 | package hr.ngs.benchmark.serializers; 2 | 3 | import de.javakaffee.kryoserializers.UUIDSerializer; 4 | 5 | import com.dslplatform.json.JsonObject; 6 | import hr.ngs.benchmark.Serializer; 7 | 8 | import java.io.IOException; 9 | import java.io.OutputStream; 10 | import java.util.UUID; 11 | 12 | public class KryoSerializer implements Serializer { 13 | private final com.esotericsoftware.kryo.Kryo kryo = new com.esotericsoftware.kryo.Kryo(); 14 | private final byte[] buffer = new byte[8192]; 15 | private final com.esotericsoftware.kryo.io.Output kryoOutput = new com.esotericsoftware.kryo.io.Output(buffer, -1); 16 | private final com.esotericsoftware.kryo.io.Input kryoInput = new com.esotericsoftware.kryo.io.Input(buffer); 17 | 18 | public KryoSerializer() { 19 | kryo.setReferences(false); 20 | kryo.register(UUID.class, new UUIDSerializer()); 21 | } 22 | 23 | @Override 24 | public void serialize(JsonObject arg, OutputStream os) throws IOException { 25 | kryoOutput.setBuffer(buffer, -1); 26 | kryo.writeObject(kryoOutput, arg); 27 | os.write(kryoOutput.getBuffer(), 0, kryoOutput.position()); 28 | } 29 | 30 | @Override 31 | public T deserialize(Class manifest, byte[] bytes, int length) throws IOException { 32 | kryoInput.setBuffer(bytes, 0, length); 33 | return (T) kryo.readObject(kryoInput, manifest); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /GatherResults/GatherResults.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {DE5D5549-0357-4BE0-A03C-622E595C49ED} 9 | Exe 10 | Properties 11 | GatherResults 12 | GatherResults 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | AnyCPU 38 | bin\Debug\ 39 | 40 | 41 | AnyCPU 42 | bin\Release\ 43 | 44 | 45 | 46 | ..\app\Newtonsoft.Json.dll 47 | 48 | 49 | ..\app\NGS.Templater.dll 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | Always 66 | 67 | 68 | 69 | 76 | -------------------------------------------------------------------------------- /GatherResults/GatherResults.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatherResults", "GatherResults.csproj", "{DE5D5549-0357-4BE0-A03C-622E595C49ED}" 7 | EndProject 8 | Global 9 | GlobalSection(DslPlatformSolutionProperties) = preSolution 10 | Php.Name = Php 11 | Php.Target = Php 12 | EndGlobalSection 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x86 = Debug|x86 16 | Release|Any CPU = Release|Any CPU 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {DE5D5549-0357-4BE0-A03C-622E595C49ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {DE5D5549-0357-4BE0-A03C-622E595C49ED}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {DE5D5549-0357-4BE0-A03C-622E595C49ED}.Debug|x86.ActiveCfg = Debug|x86 23 | {DE5D5549-0357-4BE0-A03C-622E595C49ED}.Debug|x86.Build.0 = Debug|x86 24 | {DE5D5549-0357-4BE0-A03C-622E595C49ED}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {DE5D5549-0357-4BE0-A03C-622E595C49ED}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {DE5D5549-0357-4BE0-A03C-622E595C49ED}.Release|x86.ActiveCfg = Release|x86 27 | {DE5D5549-0357-4BE0-A03C-622E595C49ED}.Release|x86.Build.0 = Release|x86 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /GatherResults/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Threading; 6 | using Newtonsoft.Json; 7 | 8 | namespace GatherResults 9 | { 10 | class Program 11 | { 12 | private static string BenchPath = "../../../app"; 13 | private static string JavaPath = Environment.GetEnvironmentVariable("JAVA_HOME"); 14 | private static string RunOnly = null; 15 | 16 | static void Main(string[] args) 17 | { 18 | if (args.Length == 2 && args[0] == "import" && File.Exists(args[1])) 19 | { 20 | File.Copy("template.xlsx", "results.xlsx", true); 21 | var vms = JsonConvert.DeserializeObject(File.ReadAllText(args[1])); 22 | using (var doc = NGS.Templater.Configuration.Factory.Open("results.xlsx")) 23 | doc.Process(vms); 24 | Process.Start("results.xlsx"); 25 | return; 26 | } 27 | if (args.Length > 0) BenchPath = args[0]; 28 | if (args.Length == 3) RunOnly = args[2]; 29 | bool exeExists = File.Exists(Path.Combine(BenchPath, "JsonBenchmark.exe")); 30 | bool jarExists = File.Exists(Path.Combine(BenchPath, "json-benchmark.jar")); 31 | if (!exeExists && !jarExists) 32 | { 33 | if (args.Length > 0 || !File.Exists("JsonBenchmark.exe")) 34 | { 35 | Console.WriteLine("Unable to find benchmark exe file: JsonBenchmark.exe in" + BenchPath); 36 | return; 37 | } 38 | if (args.Length > 0 || !File.Exists("json-benchmark.jar")) 39 | { 40 | Console.WriteLine("Unable to find benchmark jar file: json-benchmark.jar in" + BenchPath); 41 | return; 42 | } 43 | BenchPath = "."; 44 | } 45 | var java = JavaPath != null ? Path.Combine(JavaPath, "bin", "java") : "java"; 46 | var process = 47 | Process.Start( 48 | new ProcessStartInfo 49 | { 50 | FileName = java, 51 | Arguments = "-version", 52 | RedirectStandardOutput = true, 53 | UseShellExecute = false 54 | }); 55 | var javaVersion = process.StandardOutput.ReadToEnd(); 56 | Console.WriteLine(javaVersion); 57 | Console.WriteLine(".NET: " + Environment.Version); 58 | int repeat = args.Length > 1 ? int.Parse(args[1]) : 2; 59 | RunSinglePass("Warmup .NET", true, "RevenjJsonMinimal", "Small", null, 1); 60 | RunSinglePass("Warmup JVM", false, "DslJsonMinimal", "Small", null, 1); 61 | var small1 = RunSmall(repeat, 1); 62 | var std1 = RunStandard(repeat, 1); 63 | var small100k = RunSmall(repeat, 100000); 64 | var small1m = RunSmall(repeat, 1000000); 65 | var small10m = RunSmall(repeat, 10000000); 66 | RunSinglePass("Warmup .NET", true, "RevenjJsonMinimal", "Standard", null, 1); 67 | RunSinglePass("Warmup JVM", false, "DslJsonMinimal", "Standard", null, 1); 68 | var std1k = RunStandard(repeat, 1000); 69 | var std10k = RunStandard(repeat, 10000); 70 | var std100k = RunStandard(repeat, 100000); 71 | RunSinglePass("Warmup .NET", true, "RevenjJsonMinimal", "Large", null, 1); 72 | RunSinglePass("Warmup JVM", false, "DslJsonMinimal", "Large", null, 1); 73 | var large50 = RunLarge(repeat, 50); 74 | var large500 = RunLarge(repeat, 500); 75 | var outputExcel = RunOnly == null ? "results.xlsx" : RunOnly + ".xlsx"; 76 | File.Copy("template.xlsx", outputExcel, true); 77 | var vm = new ViewModel[] 78 | { 79 | ViewModel.Create("Startup times: SmallObject.Message",small1, t => t.Message), 80 | ViewModel.Create("Startup times: StandardObjects.Post", std1, t => t.Post), 81 | ViewModel.Create("100.000 SmallObjects.Message", small100k, t => t.Message), 82 | ViewModel.Create("1.000.000 SmallObjects.Message", small1m, t => t.Message), 83 | ViewModel.Create("10.000.000 SmallObjects.Message", small10m, t => t.Message), 84 | ViewModel.Create("100.000 SmallObjects.Complex", small100k, t => t.Complex), 85 | ViewModel.Create("1.000.000 SmallObjects.Complex", small1m, t => t.Complex), 86 | ViewModel.Create("10.000.000 SmallObjects.Complex", small10m, t => t.Complex), 87 | ViewModel.Create("100.000 SmallObjects.Post", small100k, t => t.Post), 88 | ViewModel.Create("1.000.000 SmallObjects.Post", small1m, t => t.Post), 89 | ViewModel.Create("10.000.000 SmallObjects.Post", small10m, t => t.Post), 90 | ViewModel.Create("1.000 StandardObjects.DeletePost", std1k, t => t.DeletePost), 91 | ViewModel.Create("10.000 StandardObjects.DeletePost", std10k, t => t.DeletePost), 92 | ViewModel.Create("100.000 StandardObjects.DeletePost", std100k, t => t.DeletePost), 93 | ViewModel.Create("1.000 StandardObjects.Post", std1k, t => t.Post), 94 | ViewModel.Create("10.000 StandardObjects.Post", std10k, t => t.Post), 95 | ViewModel.Create("100.000 StandardObjects.Post", std100k, t => t.Post), 96 | new ViewModel("50 LargeObjects.Book", large50), 97 | new ViewModel("500 LargeObjects.Book", large500), 98 | }; 99 | var json = JsonConvert.SerializeObject(vm); 100 | File.WriteAllText(RunOnly == null ? "results.json" : RunOnly + ".json", json); 101 | using (var doc = NGS.Templater.Configuration.Factory.Open(outputExcel)) 102 | doc.Process(vm); 103 | Process.Start(outputExcel); 104 | } 105 | 106 | class SmallTest 107 | { 108 | public List Message = new List(); 109 | public List Complex = new List(); 110 | public List Post = new List(); 111 | } 112 | 113 | static Run RunSmall(int times, int loops) 114 | { 115 | return new Run 116 | { 117 | Instance = RunSmall(null, times, loops), 118 | Serialization = RunSmall(false, times, loops), 119 | Both = RunSmall(true, times, loops) 120 | }; 121 | } 122 | 123 | static SmallTest RunSmall(bool? both, int times, int loops) 124 | { 125 | Console.Write("Gathering small (" + loops + ") "); 126 | Console.Write(both == null ? "instance only" : both == true ? "serialization and deserialization" : "serialization only"); 127 | var result = new SmallTest(); 128 | for (int i = 0; i < times; i++) 129 | { 130 | var d = GetherDuration("Small", both, loops); 131 | Console.Write("..."); 132 | Console.Write(i + 1); 133 | result.Message.Add(d.Extract(0)); 134 | result.Complex.Add(d.Extract(1)); 135 | result.Post.Add(d.Extract(2)); 136 | } 137 | Console.WriteLine(" ... done"); 138 | return result; 139 | } 140 | 141 | class StandardTest 142 | { 143 | public List DeletePost = new List(); 144 | public List Post = new List(); 145 | } 146 | 147 | static Run RunStandard(int times, int loops) 148 | { 149 | return new Run 150 | { 151 | Instance = RunStandard(null, times, loops), 152 | Serialization = RunStandard(false, times, loops), 153 | Both = RunStandard(true, times, loops) 154 | }; 155 | } 156 | 157 | static StandardTest RunStandard(bool? both, int times, int loops) 158 | { 159 | Console.Write("Gathering standard (" + loops + ")"); 160 | Console.Write(both == null ? "instance only" : both == true ? "serialization and deserialization" : "serialization only"); 161 | var result = new StandardTest(); 162 | for (int i = 0; i < times; i++) 163 | { 164 | var d = GetherDuration("Standard", both, loops); 165 | Console.Write("..."); 166 | Console.Write(i + 1); 167 | result.DeletePost.Add(d.Extract(0)); 168 | result.Post.Add(d.Extract(1)); 169 | } 170 | Console.WriteLine(" ... done"); 171 | return result; 172 | } 173 | 174 | static Run> RunLarge(int times, int loops) 175 | { 176 | return new Run> 177 | { 178 | Instance = RunLarge(null, times, loops), 179 | Serialization = RunLarge(false, times, loops), 180 | Both = RunLarge(true, times, loops) 181 | }; 182 | } 183 | 184 | static List RunLarge(bool? both, int times, int loops) 185 | { 186 | Console.Write("Gathering large (" + loops + ")"); 187 | Console.Write(both == null ? "instance only" : both == true ? "serialization and deserialization" : "serialization only"); 188 | var result = new List(); 189 | for (int i = 0; i < times; i++) 190 | { 191 | result.Add(GetherDuration("Large", both, loops).Extract(0)); 192 | Console.Write("..."); 193 | Console.Write(i + 1); 194 | } 195 | Console.WriteLine(" ... done"); 196 | return result; 197 | } 198 | 199 | private static readonly List EmptyStats = new List(new[]{ 200 | new Stats{ Duration = null, Size = null}, 201 | new Stats{ Duration = null, Size = null}, 202 | new Stats{ Duration = null, Size = null} 203 | }); 204 | 205 | static AggregatePass GetherDuration(string type, bool? both, int count) 206 | { 207 | var NJ = type != "Large" 208 | ? RunSinglePass("NewtonsoftJson", true, "NewtonsoftJson", type, both, count) 209 | : RunSinglePass("NewtonsoftJson", true, "RevenjNewtonsoftJson", type, both, count); 210 | var REV = RunSinglePass("Revenj", true, "RevenjJsonMinimal", type, both, count); 211 | //TODO hacks since most libraries fail 212 | var SS = type != "Large" ? RunSinglePass("Service Stack", true, "ServiceStack", type, both, count) : EmptyStats; 213 | var JIL = type != "Large" ? RunSinglePass("Jil", true, "Jil", type, both, count) : EmptyStats; 214 | var NN = type != "Large" ? RunSinglePass("NetJSON", true, "NetJSON", type, both, count) : EmptyStats; 215 | var PB = RunSinglePass("ProtoBuf", true, "ProtoBuf", type, both, count); 216 | var JJ = RunSinglePass("Jackson", false, "JacksonAfterburner", type, both, count); 217 | var JD = RunSinglePass("DSL-JSON", false, "DslJsonMinimal", type, both, count); 218 | var KR = RunSinglePass("Kryo", false, "Kryo", type, both, count); 219 | var JG = type != "Large" ? RunSinglePass("Gson", false, "Gson", type, both, count) : EmptyStats; 220 | var JB = type == "Small" ? RunSinglePass("Boon", false, "Boon", type, both, count) : EmptyStats; 221 | var JA = type != "Large" ? RunSinglePass("Alibaba", false, "Alibaba", type, both, count) : EmptyStats; 222 | return new AggregatePass 223 | { 224 | Newtonsoft = NJ, 225 | Revenj = REV, 226 | ServiceStack = SS, 227 | Jil = JIL, 228 | NetJSON = NN, 229 | Protobuf = PB, 230 | Jackson = JJ, 231 | DslJson = JD, 232 | Kryo = KR, 233 | Gson = JG, 234 | Alibaba = JA, 235 | Boon = JB 236 | }; 237 | } 238 | 239 | static List RunSinglePass(string description, bool exe, string serializer, string type, bool? both, int count) 240 | { 241 | var result = new List(); 242 | if (RunOnly != null && RunOnly != serializer) 243 | { 244 | result.Add(new Stats { Duration = null, Size = null }); 245 | result.Add(new Stats { Duration = null, Size = null }); 246 | result.Add(new Stats { Duration = null, Size = null }); 247 | return result; 248 | } 249 | var processName = exe ? Path.Combine(BenchPath, "JsonBenchmark.exe") : Path.Combine(JavaPath ?? ".", "bin", "java"); 250 | var jarArg = exe ? string.Empty : "-jar \"" + Path.Combine(BenchPath, "json-benchmark.jar") + "\" "; 251 | var what = both == null ? " None " : both == true ? " Both " : " Serialization "; 252 | var info = new ProcessStartInfo(processName, jarArg + serializer + " " + type + what + count) 253 | { 254 | UseShellExecute = false, 255 | RedirectStandardOutput = true, 256 | RedirectStandardError = true, 257 | CreateNoWindow = true 258 | }; 259 | var process = Process.Start(info); 260 | process.WaitForExit(10000 + count * 1000); 261 | if (both != null) Thread.Sleep(200);//let's wait for cleanup if required 262 | if (!process.HasExited) 263 | { 264 | Console.WriteLine(); 265 | process.Close(); 266 | try { process.Kill(); } 267 | catch { } 268 | Console.WriteLine("Timeout"); 269 | result.Add(new Stats { Duration = null, Size = null }); 270 | result.Add(new Stats { Duration = null, Size = null }); 271 | result.Add(new Stats { Duration = null, Size = null }); 272 | return result; 273 | } 274 | var lines = process.StandardOutput.ReadToEnd().Split('\n'); 275 | Console.WriteLine(); 276 | for (int i = 0; i < lines.Length / 3; i++) 277 | { 278 | var duration = lines[i * 3].Split('='); 279 | var size = lines[i * 3 + 1].Split('='); 280 | var errors = lines[i * 3 + 2].Split('='); 281 | try 282 | { 283 | Console.WriteLine(description + ": duration = " + duration[1].Trim() + ", size = " + size[1].Trim() + ", errors = " + errors[1].Trim()); 284 | if (duration[1].Trim() == "-1") 285 | result.Add(new Stats { Duration = null, Size = null }); 286 | else 287 | result.Add(new Stats { Duration = int.Parse(duration[1]), Size = long.Parse(size[1]) }); 288 | } 289 | catch 290 | { 291 | result.Add(new Stats { Duration = null, Size = null }); 292 | } 293 | } 294 | result.Add(new Stats { Duration = null, Size = null }); 295 | result.Add(new Stats { Duration = null, Size = null }); 296 | result.Add(new Stats { Duration = null, Size = null }); 297 | return result; 298 | } 299 | } 300 | 301 | struct Stats 302 | { 303 | public int? Duration; 304 | public long? Size; 305 | } 306 | 307 | class AggregatePass 308 | { 309 | public List Newtonsoft; 310 | public List Revenj; 311 | public List Jil; 312 | public List NetJSON; 313 | public List Protobuf; 314 | public List ServiceStack; 315 | public List Jackson; 316 | public List DslJson; 317 | public List Kryo; 318 | public List Gson; 319 | public List Alibaba; 320 | public List Boon; 321 | 322 | public Result Extract(int index) 323 | { 324 | return new Result 325 | { 326 | Newtonsoft = Newtonsoft[index], 327 | Revenj = Revenj[index], 328 | ServiceStack = ServiceStack[index], 329 | Jil = Jil[index], 330 | Protobuf = Protobuf[index], 331 | NetJSON = NetJSON[index], 332 | Jackson = Jackson[index], 333 | DslJson = DslJson[index], 334 | Kryo = Kryo[index], 335 | Gson = Gson[index], 336 | Alibaba = Alibaba[index], 337 | Boon = Boon[index], 338 | }; 339 | } 340 | } 341 | 342 | class Result 343 | { 344 | public Stats Newtonsoft; 345 | public Stats Revenj; 346 | public Stats Jil; 347 | public Stats Protobuf; 348 | public Stats ServiceStack; 349 | public Stats NetJSON; 350 | public Stats Jackson; 351 | public Stats DslJson; 352 | public Stats Kryo; 353 | public Stats Gson; 354 | public Stats Alibaba; 355 | public Stats Boon; 356 | } 357 | 358 | class Run 359 | { 360 | public T Instance; 361 | public T Serialization; 362 | public T Both; 363 | } 364 | 365 | class ViewModel 366 | { 367 | public string description; 368 | public List instance; 369 | public List serialization; 370 | public List both; 371 | public ViewModel() { } 372 | public ViewModel(string description, Run> run) 373 | : this(description, run.Instance, run.Serialization, run.Both) { } 374 | private ViewModel(string description, List instance, List serialization, List both) 375 | { 376 | this.description = description; 377 | this.instance = instance; 378 | this.serialization = serialization; 379 | this.both = both; 380 | } 381 | 382 | public static ViewModel Create(string description, Run run, Func> extract) 383 | { 384 | return new ViewModel(description, extract(run.Instance), extract(run.Serialization), extract(run.Both)); 385 | } 386 | } 387 | } 388 | -------------------------------------------------------------------------------- /GatherResults/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("GatherResults")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Nova generacija softvera")] 12 | [assembly: AssemblyProduct("GatherResults")] 13 | [assembly: AssemblyCopyright("Copyright © Nova generacija softvera 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("8d381380-8db6-4331-9b67-5c635157139f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /GatherResults/template.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/GatherResults/template.xlsx -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Nova Generacija Softvera d.o.o. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of Nova Generacija Softvera d.o.o. nor the names of its 15 | contributors may be used to endorse or promote products derived from this 16 | software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## .NET vs JVM JSON serialization 2 | 3 | This is reference benchmark for the fastest JSON serialization libraries in .NET and JVM. 4 | It includes various other libraries to show difference between them for various scenarios. 5 | 6 | Varieties of models are tested, from small simple objects, to very complex large objects; with different number of loops. 7 | Unlike most benchmarks which use static data for test, test data for this benchmark is created within the code. 8 | 9 | Many libraries are unable to fully complete the benchmark, due to various reasons. 10 | 11 | To give more interesting results, we'll also run tests on Mono to see how it compares to JVM/.NET. 12 | 13 | ### Models 14 | 15 | * Small: [DSL](Benchmark/SmallObjects.dsl) or [POCO](Benchmark/Models.Small.cs) 16 | * Standard: [DSL](Benchmark/StandardObjects.dsl) or [POCO](Benchmark/Models.Standard.cs) 17 | * Large: [DSL](Benchmark/LargeObjects.dsl) or [POCO](Benchmark/Models.Large.cs) 18 | 19 | ### Testing assumptions 20 | 21 | * .NET: from stream and to stream - we want to avoid LOH issues, so no `byte[]` examples (even if it could be used on small objects) - while we could use `byte[]` pool just for serialization, this bench doesn't currently test for that 22 | * JVM: from `byte[]` to `OutputStream` - while .NET reuses same stream instance, JVM libraries are consuming `byte[]` input and expected to write to the resulting stream (both objects are reused to avoid creating garbage). 23 | * single thread testing - tests are run on a single thread in a multi CPU envorionment, which tests the actual serialization algorithms and minimizes the influence of excessive GC which can be processed on other threads 24 | * simple model - tests actual serialization overhead since there is little serialization to do 25 | * standard model - non-trivial document model, should represent real world scenarios 26 | * large model - big documents - tests should be bound by non-infrastructure parts and stress underlying platform/serialization algorithms 27 | * almost default configuration - large model contains "advanced" features, such as interface serialization. 28 | * one test at a time - perform one test and exit - while this will nullify JVM optimizations in runtime, they should show up in tests with larger number of loops. 29 | * track duration of creating new object instance 30 | * some other libraries are available for testing, but not included in results (fastJSON, Genson, Microsoft Bond, FST, ...) 31 | * JMH is not used - but dead code elimination is not really an issue (one can always use Check argument to be 100% sure there is no dead code elimination). 32 | 33 | ### Libraries 34 | 35 | * **Newtonsoft.Json 9.0.1** - "Popular high-performance JSON framework for .NET" 36 | * **Revenj.Json 1.3.1** - Part of Revenj framework. POCO + serialization/deserialization methods 37 | * **Service Stack 4.0.60** - ".NET's fastest JSON Serializer" 38 | * **Jil 2.14.3** - "aims to be the fastest general purpose JSON (de)serializer for .NET" 39 | * **NetJSON 1.1.0** - "Faster than Any Binary?" 40 | * **Jackson 2.8.1** - "aims to be the best possible combination of fast, correct, lightweight, and ergonomic for developers" 41 | * **DSL-JSON 1.1.2** - DSL Platform compatibile Java library. POJO + serialization/deserialization methods 42 | * **Boon 0.6.6** - "Boon is the probably the fastest way to serialize and parse JSON in Java so far for your project" 43 | * **Alibaba/fastjson 1.2.12** - "measured to be faster than any other Java parser and databinder, includes jackson" 44 | * **Gson 2.7** - "Gson is a Java library that can be used to convert Java Objects into their JSON representation" 45 | 46 | 47 | ### Startup times 48 | 49 | It's known issue that serialization libraries suffer from startup time, since they need to build and cache parsers for types. 50 | Let's see how much of an issue that is: 51 | 52 | Small 1 (Message) 53 | 54 | ![Startup times](results/startup-small-2016-7.png) 55 | 56 | As expected baked in serialization code has minimal startup time, since it was amortized at compile time. 57 | While this can be nullified on servers with longer startup, it can cause noticeable delays on mobile apps. 58 | Java seems to be doing exceptionally well on startup times. 59 | 60 | ### Small model 61 | 62 | Model with only a few simple properties. This test mostly shows the overhead of the library since there is only little serialization to do. 63 | 64 | Small 1.000.000 (Message) 65 | 66 | ![Small objects duration](results/small-objects-2016-7.png) 67 | 68 | Since there is large number of loops JVM optimization kicks-in so it's interesting to compare it to both smaller number of loops (100k) and larger number of loops (10M). 69 | 70 | ### Non-trivial model 71 | 72 | Non-trivial model should reflect most CRUD scenarios with documents. Serialization algorithms should show difference between libraries. 73 | 74 | Standard 100.000 (Post) 75 | 76 | ![Non-trivial objects duration](results/standard-post-2016-7.png) 77 | 78 | LOH issue in .NET prohibits advanced optimizations available on JVM (in a sense that developers are forced to deal with it, instead of focusing on algorithms). 79 | 80 | ### Large model 81 | 82 | Large model contains several advanced features, such as interface serialization, occasional byte[] serialization and deep nested objects. 83 | Large strings and other objects are used which cause 10x slower instance creation in .NET. 84 | 85 | Large 500 (Book) 86 | 87 | ![Large objects duration](results/large-500-2016-7.png) 88 | 89 | Most libraries are unable to complete this bench (due to requirement for advanced features; Jackson gets some help through annotations). 90 | 91 | ### Mono comparison (results for 2016/4) 92 | 93 | Mono has improved significantly with v4. 94 | 95 | Small 10.000.000 (Post) 96 | 97 | ![.NET vs Mono](results/net-vs-mono-2016.png) 98 | 99 | It's only twice as slow as .NET version. 100 | 101 | ### Full results 102 | 103 | #### 2015/6 104 | 105 | AMD Phenom(tm) II X4 955 Processor 3.20 GHz / 24GB RAM 106 | 107 | .NET 4.5.1, Mono 4.0.1, JVM 1.7.76/1.8.31 108 | 109 | Results for [Windows](results/results-windows-2015.xlsx). 110 | Results for [Linux](results/results-linux-2015.xlsx). 111 | .NET vs Mono [comparison](results/result-dotnet-vs-mono-2015.xlsx). 112 | 113 | #### 2016/4 114 | 115 | AMD Phenom(tm) II X4 955 Processor 3.20 GHz / 24GB RAM 116 | 117 | .NET 4.6.2, Mono 4.2.3, JVM 1.8.77 118 | 119 | Results for [Windows](results/results-windows-2016.xlsx). 120 | Results for [Linux](results/results-linux-2016.xlsx). 121 | .NET vs Mono [comparison](results/result-dotnet-vs-mono-2016.xlsx). 122 | 123 | #### 2016/7 124 | 125 | Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz / 16GB RAM 126 | 127 | .NET 4.6.2, JVM 1.8.102 128 | 129 | Results for [Windows](results/results-windows-2016-7.xlsx). 130 | 131 | ### Reproducing results 132 | 133 | Run [GatherResults.exe](app/GatherResults.exe) or *GatherResults.exe . 5* 134 | 135 | Individual tests can be run as: 136 | 137 | * .NET: [JsonBenchmark.exe](app/JsonBenchmark.exe) (example: *JsonBenchmark.exe RevenjJsonMinimal Small Both 1000000*) 138 | * JVM: [json-benchmark.jar](app/json-benchmark.jar) (example: *java -jar json-benchmark.jar Jackson Standard Serialization 100000*) 139 | 140 | If you are interested in changing the models, then you can: 141 | 142 | * install Visual studio plugin: [DDD for DSL](https://visualstudiogallery.msdn.microsoft.com/5b8a140c-5c84-40fc-a551-b255ba7676f4) 143 | * or use [dsl-clc.jar with compile.bat](Benchmark/0-compile-model.bat) 144 | 145 | If you want to test other libraries run benchmark without arguments to find out which libraries are available. For example to test Microsoft Bond run: *JsonBenchmark.exe BondBinary Small Both 1000000*. 146 | 147 | To check if library is working correctly, use **Check** argument. Some libraries are reported to work incorrectly but still included in results (Service Stack serializes only 3 digits on DateTime, which causes incorrect comparison after deserialization, ...) 148 | 149 | ### Conclusions 150 | 151 | * JVM seems to always be faster after optimization kicks-in 152 | * LOH design issue forces .NET libraries to use suboptimal algorithms 153 | * Newtonsoft is comparable with Jackson on features/quality but not in speed 154 | * .NET libraries have matured over time (although most of them still have various issues) 155 | * Almost everyone claims to be THE FASTEST 156 | * JSON can compete with binary codecs in speed 157 | -------------------------------------------------------------------------------- /app/Bond.Attributes.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Bond.Attributes.dll -------------------------------------------------------------------------------- /app/Bond.IO.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Bond.IO.dll -------------------------------------------------------------------------------- /app/Bond.JSON.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Bond.JSON.dll -------------------------------------------------------------------------------- /app/Bond.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Bond.dll -------------------------------------------------------------------------------- /app/GatherResults.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/GatherResults.exe -------------------------------------------------------------------------------- /app/Jil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Jil.dll -------------------------------------------------------------------------------- /app/JsonBenchmark.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/JsonBenchmark.exe -------------------------------------------------------------------------------- /app/JsonBenchmark.exe.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/NGS.Templater.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/NGS.Templater.dll -------------------------------------------------------------------------------- /app/NetJSON.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/NetJSON.dll -------------------------------------------------------------------------------- /app/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /app/Revenj.Common.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Revenj.Common.dll -------------------------------------------------------------------------------- /app/Revenj.DomainPatterns.Interface.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Revenj.DomainPatterns.Interface.dll -------------------------------------------------------------------------------- /app/Revenj.DomainPatterns.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Revenj.DomainPatterns.dll -------------------------------------------------------------------------------- /app/Revenj.Extensibility.Interface.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Revenj.Extensibility.Interface.dll -------------------------------------------------------------------------------- /app/Revenj.Serialization.Interface.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Revenj.Serialization.Interface.dll -------------------------------------------------------------------------------- /app/Revenj.Serialization.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Revenj.Serialization.dll -------------------------------------------------------------------------------- /app/Revenj.Utility.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Revenj.Utility.dll -------------------------------------------------------------------------------- /app/ServerModel.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/ServerModel.dll -------------------------------------------------------------------------------- /app/ServiceStack.Text.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/ServiceStack.Text.dll -------------------------------------------------------------------------------- /app/Sigil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/Sigil.dll -------------------------------------------------------------------------------- /app/fastJSON.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/fastJSON.dll -------------------------------------------------------------------------------- /app/json-benchmark.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/json-benchmark.jar -------------------------------------------------------------------------------- /app/protobuf-net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/protobuf-net.dll -------------------------------------------------------------------------------- /app/template.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/app/template.xlsx -------------------------------------------------------------------------------- /results/large-1000-2015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/large-1000-2015.png -------------------------------------------------------------------------------- /results/large-1000-2016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/large-1000-2016.png -------------------------------------------------------------------------------- /results/large-500-2016-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/large-500-2016-7.png -------------------------------------------------------------------------------- /results/net-vs-mono-2015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/net-vs-mono-2015.png -------------------------------------------------------------------------------- /results/net-vs-mono-2016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/net-vs-mono-2016.png -------------------------------------------------------------------------------- /results/result-dotnet-vs-mono-2015.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/result-dotnet-vs-mono-2015.xlsx -------------------------------------------------------------------------------- /results/result-dotnet-vs-mono-2016.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/result-dotnet-vs-mono-2016.xlsx -------------------------------------------------------------------------------- /results/results-linux-2015.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/results-linux-2015.xlsx -------------------------------------------------------------------------------- /results/results-linux-2016.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/results-linux-2016.xlsx -------------------------------------------------------------------------------- /results/results-windows-2015.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/results-windows-2015.xlsx -------------------------------------------------------------------------------- /results/results-windows-2016-7.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/results-windows-2016-7.xlsx -------------------------------------------------------------------------------- /results/results-windows-2016.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/results-windows-2016.xlsx -------------------------------------------------------------------------------- /results/small-complex-2016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/small-complex-2016.png -------------------------------------------------------------------------------- /results/small-objects-2015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/small-objects-2015.png -------------------------------------------------------------------------------- /results/small-objects-2016-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/small-objects-2016-7.png -------------------------------------------------------------------------------- /results/small-objects-2016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/small-objects-2016.png -------------------------------------------------------------------------------- /results/standard-post-2015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/standard-post-2015.png -------------------------------------------------------------------------------- /results/standard-post-2016-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/standard-post-2016-7.png -------------------------------------------------------------------------------- /results/standard-post-2016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/standard-post-2016.png -------------------------------------------------------------------------------- /results/startup-small-2015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/startup-small-2015.png -------------------------------------------------------------------------------- /results/startup-small-2016-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/startup-small-2016-7.png -------------------------------------------------------------------------------- /results/startup-small-2016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngs-doo/json-benchmark/83634bbf08dd83dabf3b585d4de8c29fddcd5b17/results/startup-small-2016.png --------------------------------------------------------------------------------