-
Notifications
You must be signed in to change notification settings - Fork 273
/
Copy pathPerf.Reader.cs
149 lines (134 loc) · 5.51 KB
/
Perf.Reader.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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
137
138
139
140
141
142
143
144
145
146
147
148
149
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using BenchmarkDotNet.Attributes;
using MicroBenchmarks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Buffers;
using System.IO;
using System.Memory;
namespace System.Text.Json.Tests
{
[BenchmarkCategory(Categories.Libraries, Categories.JSON)]
public class Perf_Reader
{
// Keep the JsonStrings resource names in sync with TestCaseType enum values.
public enum TestCaseType
{
HelloWorld,
DeepTree,
BroadTree,
LotsOfNumbers,
LotsOfStrings,
Json400B,
Json4KB,
Json40KB
}
private string _jsonString;
private byte[] _dataUtf8;
private ReadOnlySequence<byte> _sequence;
private ReadOnlySequence<byte> _sequenceSingle;
private byte[] _destination;
[ParamsAllValues]
public TestCaseType TestCase;
[Params(true, false)]
public bool IsDataCompact;
[GlobalSetup]
public void Setup()
{
_jsonString = JsonStrings.ResourceManager.GetString(TestCase.ToString());
// Remove all formatting/indendation
if (IsDataCompact)
{
using (var jsonReader = new JsonTextReader(new StringReader(_jsonString)))
using (var stringWriter = new StringWriter())
using (var jsonWriter = new JsonTextWriter(stringWriter))
{
JToken obj = JToken.ReadFrom(jsonReader);
obj.WriteTo(jsonWriter);
_jsonString = stringWriter.ToString();
}
}
_dataUtf8 = Encoding.UTF8.GetBytes(_jsonString);
ReadOnlyMemory<byte> dataMemory = _dataUtf8;
_sequenceSingle = new ReadOnlySequence<byte>(dataMemory);
var firstSegment = new BufferSegment<byte>(dataMemory.Slice(0, _dataUtf8.Length / 2));
ReadOnlyMemory<byte> secondMem = dataMemory.Slice(_dataUtf8.Length / 2);
BufferSegment<byte> secondSegment = firstSegment.Append(secondMem);
_sequence = new ReadOnlySequence<byte>(firstSegment, 0, secondSegment, secondMem.Length);
_destination = new byte[_dataUtf8.Length * 2];
}
[Benchmark]
public void ReadSpanEmptyLoop()
{
var json = new Utf8JsonReader(_dataUtf8);
while (json.Read()) ;
}
[Benchmark]
public void ReadSingleSpanSequenceEmptyLoop()
{
var json = new Utf8JsonReader(_sequenceSingle);
while (json.Read()) ;
}
[Benchmark]
public void ReadMultiSpanSequenceEmptyLoop()
{
var json = new Utf8JsonReader(_sequence);
while (json.Read()) ;
}
[Benchmark]
public byte[] ReadReturnBytes()
{
Span<byte> destination = _destination;
var json = new Utf8JsonReader(_dataUtf8);
while (json.Read())
{
JsonTokenType tokenType = json.TokenType;
ReadOnlySpan<byte> valueSpan = json.ValueSpan;
switch (tokenType)
{
case JsonTokenType.PropertyName:
valueSpan.CopyTo(destination);
destination[valueSpan.Length] = (byte)',';
destination[valueSpan.Length + 1] = (byte)' ';
destination = destination.Slice(valueSpan.Length + 2);
break;
case JsonTokenType.Number:
case JsonTokenType.String:
valueSpan.CopyTo(destination);
destination[valueSpan.Length] = (byte)',';
destination[valueSpan.Length + 1] = (byte)' ';
destination = destination.Slice(valueSpan.Length + 2);
break;
case JsonTokenType.True:
// Special casing True/False so that the casing matches with Json.NET
destination[0] = (byte)'T';
destination[1] = (byte)'r';
destination[2] = (byte)'u';
destination[3] = (byte)'e';
destination[valueSpan.Length] = (byte)',';
destination[valueSpan.Length + 1] = (byte)' ';
destination = destination.Slice(valueSpan.Length + 2);
break;
case JsonTokenType.False:
destination[0] = (byte)'F';
destination[1] = (byte)'a';
destination[2] = (byte)'l';
destination[3] = (byte)'s';
destination[4] = (byte)'e';
destination[valueSpan.Length] = (byte)',';
destination[valueSpan.Length + 1] = (byte)' ';
destination = destination.Slice(valueSpan.Length + 2);
break;
case JsonTokenType.Null:
// Special casing Null so that it matches what JSON.NET does
break;
default:
break;
}
}
return _destination;
}
}
}