optimize initialization of ParseContext

pull/7351/head
Jan Tattermusch 5 years ago
parent d17b5115d2
commit 07182a843c
  1. 2
      csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs
  2. 16
      csharp/src/Google.Protobuf.Benchmarks/ParseRawPrimitivesBenchmark.cs
  3. 6
      csharp/src/Google.Protobuf/CodedInputStream.cs
  4. 2
      csharp/src/Google.Protobuf/Collections/MapField.cs
  5. 2
      csharp/src/Google.Protobuf/Collections/RepeatedField.cs
  6. 2
      csharp/src/Google.Protobuf/ExtensionValue.cs
  7. 2
      csharp/src/Google.Protobuf/FieldCodec.cs
  8. 2
      csharp/src/Google.Protobuf/MessageExtensions.cs
  9. 49
      csharp/src/Google.Protobuf/ParseContext.cs
  10. 2
      csharp/src/Google.Protobuf/UnknownFieldSet.cs

@ -195,7 +195,7 @@ namespace Google.Protobuf.Benchmarks
public void ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
{
var ctx = new ParseContext(multipleMessagesDataSequence);
ParseContext.Initialize(multipleMessagesDataSequence, out ParseContext ctx);
for (int i = 0; i < messageCount; i++)
{
var msg = factory();

@ -105,7 +105,7 @@ namespace Google.Protobuf.Benchmarks
[Arguments(5)]
public int ParseRawVarint32_ParseContext(int encodedSize)
{
var ctx = CreateParseContext(varintInputBuffers[encodedSize]);
InitializeParseContext(varintInputBuffers[encodedSize], out ParseContext ctx);
int sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
@ -149,7 +149,7 @@ namespace Google.Protobuf.Benchmarks
[Arguments(10)]
public long ParseRawVarint64_ParseContext(int encodedSize)
{
var ctx = CreateParseContext(varintInputBuffers[encodedSize]);
InitializeParseContext(varintInputBuffers[encodedSize], out ParseContext ctx);
long sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
@ -175,7 +175,7 @@ namespace Google.Protobuf.Benchmarks
public uint ParseFixed32_ParseContext()
{
const int encodedSize = sizeof(uint);
var ctx = CreateParseContext(fixedIntInputBuffer);
InitializeParseContext(fixedIntInputBuffer, out ParseContext ctx);
uint sum = 0;
for (uint i = 0; i < BytesToParse / encodedSize; i++)
{
@ -201,7 +201,7 @@ namespace Google.Protobuf.Benchmarks
public ulong ParseFixed64_ParseContext()
{
const int encodedSize = sizeof(ulong);
var ctx = CreateParseContext(fixedIntInputBuffer);
InitializeParseContext(fixedIntInputBuffer, out ParseContext ctx);
ulong sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
@ -227,7 +227,7 @@ namespace Google.Protobuf.Benchmarks
public float ParseRawFloat_ParseContext()
{
const int encodedSize = sizeof(float);
var ctx = CreateParseContext(floatInputBuffer);
InitializeParseContext(floatInputBuffer, out ParseContext ctx);
float sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
@ -253,7 +253,7 @@ namespace Google.Protobuf.Benchmarks
public double ParseRawDouble_ParseContext()
{
const int encodedSize = sizeof(double);
var ctx = CreateParseContext(doubleInputBuffer);
InitializeParseContext(doubleInputBuffer, out ParseContext ctx);
double sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
@ -262,9 +262,9 @@ namespace Google.Protobuf.Benchmarks
return sum;
}
private static ParseContext CreateParseContext(byte[] buffer)
private static void InitializeParseContext(byte[] buffer, out ParseContext ctx)
{
return new ParseContext(new ReadOnlySequence<byte>(buffer));
ParseContext.Initialize(new ReadOnlySequence<byte>(buffer), out ctx);
}
private static byte[] CreateBufferWithRandomVarints(Random random, int valueCount, int encodedSize, int paddingValueCount)

@ -431,7 +431,7 @@ namespace Google.Protobuf
public void ReadMessage(IMessage builder)
{
var span = new ReadOnlySpan<byte>(buffer);
var ctx = new ParseContext(ref span, ref state);
ParseContext.Initialize(ref span, ref state, out ParseContext ctx);
try
{
ParsingPrimitivesMessages.ReadMessage(ref ctx, builder);
@ -447,7 +447,7 @@ namespace Google.Protobuf
/// </summary>
public void ReadGroup(IMessage builder)
{
var ctx = new ParseContext(this);
ParseContext.Initialize(this, out ParseContext ctx);
try
{
ParsingPrimitivesMessages.ReadGroup(ref ctx, builder);
@ -691,7 +691,7 @@ namespace Google.Protobuf
/// </summary>
public void ReadRawMessage(IMessage message)
{
var ctx = new ParseContext(this);
ParseContext.Initialize(this, out ParseContext ctx);
try
{
ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message);

@ -713,7 +713,7 @@ namespace Google.Protobuf.Collections
// Read it as if we'd seen input with no data (i.e. create a "default" message).
if (Value == null)
{
var zeroLengthCtx = new ParseContext(new ReadOnlySequence<byte>(ZeroLengthMessageStreamData));
ParseContext.Initialize(new ReadOnlySequence<byte>(ZeroLengthMessageStreamData), out ParseContext zeroLengthCtx);
Value = codec.valueCodec.Read(ref zeroLengthCtx);
}
}

@ -95,7 +95,7 @@ namespace Google.Protobuf.Collections
/// <param name="codec">The codec to use in order to read each entry.</param>
public void AddEntriesFrom(CodedInputStream input, FieldCodec<T> codec)
{
var ctx = new ParseContext(input);
ParseContext.Initialize(input, out ParseContext ctx);
try
{
AddEntriesFrom(ref ctx, codec);

@ -96,7 +96,7 @@ namespace Google.Protobuf
public void MergeFrom(CodedInputStream input)
{
var ctx = new ParseContext(input);
ParseContext.Initialize(input, out ParseContext ctx);
try
{
codec.ValueMerger(ref ctx, ref field);

@ -844,7 +844,7 @@ namespace Google.Protobuf
/// <returns>The value read from the stream.</returns>
public T Read(CodedInputStream input)
{
var ctx = new ParseContext(input);
ParseContext.Initialize(input, out ParseContext ctx);
try
{
return ValueReader(ref ctx);

@ -253,7 +253,7 @@ namespace Google.Protobuf
[SecuritySafeCritical]
internal static void MergeFrom(this IMessage message, ReadOnlySequence<byte> data, bool discardUnknownFields, ExtensionRegistry registry)
{
var ctx = new ParseContext(data);
ParseContext.Initialize(data, out ParseContext ctx);
ctx.DiscardUnknownFields = discardUnknownFields;
ctx.ExtensionRegistry = registry;
ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message);

@ -58,10 +58,11 @@ namespace Google.Protobuf
internal ReadOnlySpan<byte> buffer;
internal ParserInternalState state;
internal ParseContext(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Initialize(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state, out ParseContext ctx)
{
this.buffer = buffer;
this.state = state;
ctx.buffer = buffer;
ctx.state = state;
}
/// <summary>
@ -69,33 +70,37 @@ namespace Google.Protobuf
/// WARNING: internally this copies the CodedInputStream's state, so after done with the ParseContext,
/// the CodedInputStream's state needs to be updated.
/// </summary>
internal ParseContext(CodedInputStream input)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Initialize(CodedInputStream input, out ParseContext ctx)
{
this.buffer = new ReadOnlySpan<byte>(input.InternalBuffer);
ctx.buffer = new ReadOnlySpan<byte>(input.InternalBuffer);
// TODO: ideally we would use a reference to the original state, but that doesn't seem possible
this.state = input.InternalState; // creates copy of the state
ctx.state = input.InternalState; // creates copy of the state
}
internal ParseContext(ReadOnlySequence<byte> input) : this(input, DefaultRecursionLimit)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Initialize(ReadOnlySequence<byte> input, out ParseContext ctx)
{
Initialize(input, DefaultRecursionLimit, out ctx);
}
internal ParseContext(ReadOnlySequence<byte> input, int recursionLimit)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Initialize(ReadOnlySequence<byte> input, int recursionLimit, out ParseContext ctx)
{
this.buffer = default;
this.state = default;
this.state.lastTag = 0;
this.state.recursionDepth = 0;
this.state.sizeLimit = DefaultSizeLimit;
this.state.recursionLimit = recursionLimit;
this.state.currentLimit = int.MaxValue;
SegmentedBufferHelper.Initialize(input, out this.state.segmentedBufferHelper, out this.buffer);
this.state.bufferPos = 0;
this.state.bufferSize = this.buffer.Length;
this.state.codedInputStream = null;
this.state.DiscardUnknownFields = false;
this.state.ExtensionRegistry = null;
ctx.buffer = default;
ctx.state = default;
ctx.state.lastTag = 0;
ctx.state.recursionDepth = 0;
ctx.state.sizeLimit = DefaultSizeLimit;
ctx.state.recursionLimit = recursionLimit;
ctx.state.currentLimit = int.MaxValue;
SegmentedBufferHelper.Initialize(input, out ctx.state.segmentedBufferHelper, out ctx.buffer);
ctx.state.bufferPos = 0;
ctx.state.bufferSize = ctx.buffer.Length;
ctx.state.codedInputStream = null;
ctx.state.DiscardUnknownFields = false;
ctx.state.ExtensionRegistry = null;
}
/// <summary>

@ -258,7 +258,7 @@ namespace Google.Protobuf
public static UnknownFieldSet MergeFieldFrom(UnknownFieldSet unknownFields,
CodedInputStream input)
{
var ctx = new ParseContext(input);
ParseContext.Initialize(input, out ParseContext ctx);
try
{
return MergeFieldFrom(unknownFields, ref ctx);

Loading…
Cancel
Save