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 |