Skip to content

Commit d963fd9

Browse files
committed
Add CodedInputReader and CodedOutputWriter
1 parent 129a7c8 commit d963fd9

16 files changed

+4906
-373
lines changed

csharp/src/Google.Protobuf.Benchmarks/BenchmarkMessage1Proto3.cs

+676-7
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#region Copyright notice and license
2+
// Protocol Buffers - Google's data interchange format
3+
// Copyright 2019 Google Inc. All rights reserved.
4+
// https://github.com/protocolbuffers/protobuf
5+
//
6+
// Redistribution and use in source and binary forms, with or without
7+
// modification, are permitted provided that the following conditions are
8+
// met:
9+
//
10+
// * Redistributions of source code must retain the above copyright
11+
// notice, this list of conditions and the following disclaimer.
12+
// * Redistributions in binary form must reproduce the above
13+
// copyright notice, this list of conditions and the following disclaimer
14+
// in the documentation and/or other materials provided with the
15+
// distribution.
16+
// * Neither the name of Google Inc. nor the names of its
17+
// contributors may be used to endorse or promote products derived from
18+
// this software without specific prior written permission.
19+
//
20+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
#endregion
32+
33+
using BenchmarkDotNet.Attributes;
34+
using Benchmarks.Proto3;
35+
using System;
36+
using System.Buffers;
37+
using System.Collections.Generic;
38+
using System.IO;
39+
using System.Linq;
40+
41+
namespace Google.Protobuf.Benchmarks
42+
{
43+
[MemoryDiagnoser]
44+
public class JamesBenchmarks
45+
{
46+
private GoogleMessage1 _message;
47+
private byte[] _messageData;
48+
private int _messageSize;
49+
private BufferWriter _bufferWriter;
50+
private ReadOnlySequence<byte> _readOnlySequence;
51+
52+
[GlobalSetup]
53+
public void GlobalSetup()
54+
{
55+
MemoryStream ms = new MemoryStream();
56+
CodedOutputStream output = new CodedOutputStream(ms);
57+
58+
GoogleMessage1 googleMessage1 = new GoogleMessage1();
59+
googleMessage1.Field1 = "Text" + new string('!', 200);
60+
googleMessage1.Field2 = 2;
61+
googleMessage1.Field15 = new GoogleMessage1SubMessage();
62+
googleMessage1.Field15.Field1 = 1;
63+
64+
googleMessage1.WriteTo(output);
65+
output.Flush();
66+
67+
_message = googleMessage1;
68+
_messageData = ms.ToArray();
69+
_messageSize = googleMessage1.CalculateSize();
70+
71+
_bufferWriter = new BufferWriter(new byte[_messageSize]);
72+
_readOnlySequence = new ReadOnlySequence<byte>(_messageData);
73+
}
74+
75+
[Benchmark]
76+
public void WriteToByteArray()
77+
{
78+
CodedOutputStream output = new CodedOutputStream(new byte[_messageSize]);
79+
80+
_message.WriteTo(output);
81+
}
82+
83+
[Benchmark]
84+
public void ParseFromByteArray()
85+
{
86+
var messageData = new byte[_messageData.Length];
87+
Array.Copy(_messageData, messageData, _messageData.Length);
88+
89+
CodedInputStream input = new CodedInputStream(messageData);
90+
91+
GoogleMessage1 message = new GoogleMessage1();
92+
message.MergeFrom(input);
93+
}
94+
95+
[Benchmark]
96+
public void WriteToBufferWriter()
97+
{
98+
CodedOutputWriter output = new CodedOutputWriter(_bufferWriter);
99+
100+
_message.WriteTo(ref output);
101+
102+
_bufferWriter.Reset();
103+
}
104+
105+
[Benchmark]
106+
public void ParseFromReadOnlySequence()
107+
{
108+
CodedInputReader input = new CodedInputReader(_readOnlySequence);
109+
110+
GoogleMessage1 message = new GoogleMessage1();
111+
message.MergeFrom(ref input);
112+
}
113+
}
114+
115+
internal class BufferWriter : IBufferWriter<byte>
116+
{
117+
private readonly byte[] _buffer;
118+
private int _position;
119+
120+
public BufferWriter(byte[] buffer)
121+
{
122+
_buffer = buffer;
123+
}
124+
125+
public void Advance(int count)
126+
{
127+
_position += count;
128+
}
129+
130+
public void Reset()
131+
{
132+
_position = 0;
133+
}
134+
135+
public Memory<byte> GetMemory(int sizeHint = 0)
136+
{
137+
return _buffer.AsMemory(_position);
138+
}
139+
140+
public Span<byte> GetSpan(int sizeHint = 0)
141+
{
142+
return _buffer.AsSpan(_position);
143+
}
144+
}
145+
}

csharp/src/Google.Protobuf.Benchmarks/Program.cs

+12-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ namespace Google.Protobuf.Benchmarks
4141
/// </summary>
4242
class Program
4343
{
44-
static void Main() => BenchmarkRunner.Run<SerializationBenchmark>();
44+
#if true
45+
static void Main() => BenchmarkRunner.Run<JamesBenchmarks>();
46+
#else
47+
static void Main()
48+
{
49+
var b = new JamesBenchmarks();
50+
b.GlobalSetup();
51+
52+
b.ParseFromReadOnlySequence();
53+
//b.ParseFromByteArray();
54+
}
55+
#endif
4556
}
4657
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#region Copyright notice and license
2+
// Protocol Buffers - Google's data interchange format
3+
// Copyright 2008 Google Inc. All rights reserved.
4+
// https://developers.google.com/protocol-buffers/
5+
//
6+
// Redistribution and use in source and binary forms, with or without
7+
// modification, are permitted provided that the following conditions are
8+
// met:
9+
//
10+
// * Redistributions of source code must retain the above copyright
11+
// notice, this list of conditions and the following disclaimer.
12+
// * Redistributions in binary form must reproduce the above
13+
// copyright notice, this list of conditions and the following disclaimer
14+
// in the documentation and/or other materials provided with the
15+
// distribution.
16+
// * Neither the name of Google Inc. nor the names of its
17+
// contributors may be used to endorse or promote products derived from
18+
// this software without specific prior written permission.
19+
//
20+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
#endregion
32+
33+
#if NETCOREAPP2_1
34+
using System;
35+
using System.Buffers;
36+
using System.Collections.Generic;
37+
using System.Runtime.CompilerServices;
38+
using System.Text;
39+
40+
namespace Google.Protobuf
41+
{
42+
internal class ArrayBufferWriter : IBufferWriter<byte>, IDisposable
43+
{
44+
private ResizableArray<byte> _buffer;
45+
private readonly int _maximumSizeHint;
46+
47+
public ArrayBufferWriter(int capacity, int? maximumSizeHint = null)
48+
{
49+
_buffer = new ResizableArray<byte>(ArrayPool<byte>.Shared.Rent(capacity));
50+
_maximumSizeHint = maximumSizeHint ?? int.MaxValue;
51+
}
52+
53+
public int CommitedByteCount => _buffer.Count;
54+
55+
public void Clear()
56+
{
57+
_buffer.Count = 0;
58+
}
59+
60+
public ArraySegment<byte> Free => _buffer.Free;
61+
62+
public ArraySegment<byte> Formatted => _buffer.Full;
63+
64+
public Memory<byte> GetMemory(int minimumLength = 0)
65+
{
66+
minimumLength = Math.Min(minimumLength, _maximumSizeHint);
67+
68+
if (minimumLength < 1)
69+
{
70+
minimumLength = 1;
71+
}
72+
73+
if (minimumLength > _buffer.FreeCount)
74+
{
75+
int doubleCount = _buffer.FreeCount * 2;
76+
int newSize = minimumLength > doubleCount ? minimumLength : doubleCount;
77+
byte[] newArray = ArrayPool<byte>.Shared.Rent(newSize + _buffer.Count);
78+
byte[] oldArray = _buffer.Resize(newArray);
79+
ArrayPool<byte>.Shared.Return(oldArray);
80+
}
81+
82+
return _buffer.FreeMemory;
83+
}
84+
85+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
86+
public Span<byte> GetSpan(int minimumLength = 0)
87+
{
88+
minimumLength = Math.Min(minimumLength, _maximumSizeHint);
89+
90+
if (minimumLength < 1)
91+
{
92+
minimumLength = 1;
93+
}
94+
95+
if (minimumLength > _buffer.FreeCount)
96+
{
97+
int doubleCount = _buffer.FreeCount * 2;
98+
int newSize = minimumLength > doubleCount ? minimumLength : doubleCount;
99+
byte[] newArray = ArrayPool<byte>.Shared.Rent(newSize + _buffer.Count);
100+
byte[] oldArray = _buffer.Resize(newArray);
101+
ArrayPool<byte>.Shared.Return(oldArray);
102+
}
103+
104+
return _buffer.FreeSpan;
105+
}
106+
107+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
108+
public void Advance(int bytes)
109+
{
110+
_buffer.Count += bytes;
111+
if (_buffer.Count > _buffer.Capacity)
112+
{
113+
throw new InvalidOperationException("More bytes commited than returned from FreeBuffer");
114+
}
115+
}
116+
117+
public void Dispose()
118+
{
119+
byte[] array = _buffer.Array;
120+
_buffer.Array = null;
121+
ArrayPool<byte>.Shared.Return(array);
122+
}
123+
124+
private struct ResizableArray<T>
125+
{
126+
public ResizableArray(T[] array, int count = 0)
127+
{
128+
Array = array;
129+
Count = count;
130+
}
131+
132+
public T[] Array { get; set; }
133+
134+
public int Count { get; set; }
135+
136+
public int Capacity => Array.Length;
137+
138+
public T[] Resize(T[] newArray)
139+
{
140+
T[] oldArray = Array;
141+
Array.AsSpan(0, Count).CopyTo(newArray); // CopyTo will throw if newArray.Length < _count
142+
Array = newArray;
143+
return oldArray;
144+
}
145+
146+
public ArraySegment<T> Full => new ArraySegment<T>(Array, 0, Count);
147+
148+
public ArraySegment<T> Free => new ArraySegment<T>(Array, Count, Array.Length - Count);
149+
150+
public Span<T> FreeSpan => new Span<T>(Array, Count, Array.Length - Count);
151+
152+
public Memory<T> FreeMemory => new Memory<T>(Array, Count, Array.Length - Count);
153+
154+
public int FreeCount => Array.Length - Count;
155+
}
156+
}
157+
}
158+
#endif

0 commit comments

Comments
 (0)