Merge pull request #7576 from jtattermusch/protobuf_buffer_serialization
New Span-based serialization logic (followup for #7351)pull/7660/head
commit
206b973afd
80 changed files with 11022 additions and 628 deletions
@ -0,0 +1,198 @@ |
||||
#region Copyright notice and license |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2019 Google Inc. All rights reserved. |
||||
// https://github.com/protocolbuffers/protobuf |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
#endregion |
||||
|
||||
using BenchmarkDotNet.Attributes; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Buffers; |
||||
using Google.Protobuf.WellKnownTypes; |
||||
|
||||
namespace Google.Protobuf.Benchmarks |
||||
{ |
||||
/// <summary> |
||||
/// Benchmark that tests writing performance for various messages. |
||||
/// </summary> |
||||
[MemoryDiagnoser] |
||||
public class WriteMessagesBenchmark |
||||
{ |
||||
const int MaxMessages = 100; |
||||
|
||||
SubTest manyWrapperFieldsTest = new SubTest(ParseMessagesBenchmark.CreateManyWrapperFieldsMessage(), MaxMessages); |
||||
SubTest manyPrimitiveFieldsTest = new SubTest(ParseMessagesBenchmark.CreateManyPrimitiveFieldsMessage(), MaxMessages); |
||||
SubTest emptyMessageTest = new SubTest(new Empty(), MaxMessages); |
||||
|
||||
public IEnumerable<int> MessageCountValues => new[] { 10, 100 }; |
||||
|
||||
[GlobalSetup] |
||||
public void GlobalSetup() |
||||
{ |
||||
} |
||||
|
||||
[Benchmark] |
||||
public byte[] ManyWrapperFieldsMessage_ToByteArray() |
||||
{ |
||||
return manyWrapperFieldsTest.ToByteArray(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public byte[] ManyWrapperFieldsMessage_WriteToCodedOutputStream() |
||||
{ |
||||
return manyWrapperFieldsTest.WriteToCodedOutputStream_PreAllocatedBuffer(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public byte[] ManyWrapperFieldsMessage_WriteToSpan() |
||||
{ |
||||
return manyWrapperFieldsTest.WriteToSpan_PreAllocatedBuffer(); |
||||
} |
||||
|
||||
|
||||
[Benchmark] |
||||
public byte[] ManyPrimitiveFieldsMessage_ToByteArray() |
||||
{ |
||||
return manyPrimitiveFieldsTest.ToByteArray(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public byte[] ManyPrimitiveFieldsMessage_WriteToCodedOutputStream() |
||||
{ |
||||
return manyPrimitiveFieldsTest.WriteToCodedOutputStream_PreAllocatedBuffer(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public byte[] ManyPrimitiveFieldsMessage_WriteToSpan() |
||||
{ |
||||
return manyPrimitiveFieldsTest.WriteToSpan_PreAllocatedBuffer(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public byte[] EmptyMessage_ToByteArray() |
||||
{ |
||||
return emptyMessageTest.ToByteArray(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public byte[] EmptyMessage_WriteToCodedOutputStream() |
||||
{ |
||||
return emptyMessageTest.WriteToCodedOutputStream_PreAllocatedBuffer(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public byte[] EmptyMessage_WriteToSpan() |
||||
{ |
||||
return emptyMessageTest.WriteToSpan_PreAllocatedBuffer(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(MessageCountValues))] |
||||
public void ManyWrapperFieldsMessage_WriteDelimitedMessagesToCodedOutputStream(int messageCount) |
||||
{ |
||||
manyWrapperFieldsTest.WriteDelimitedMessagesToCodedOutputStream_PreAllocatedBuffer(messageCount); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(MessageCountValues))] |
||||
public void ManyWrapperFieldsMessage_WriteDelimitedMessagesToSpan(int messageCount) |
||||
{ |
||||
manyWrapperFieldsTest.WriteDelimitedMessagesToSpan_PreAllocatedBuffer(messageCount); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(MessageCountValues))] |
||||
public void ManyPrimitiveFieldsMessage_WriteDelimitedMessagesToCodedOutputStream(int messageCount) |
||||
{ |
||||
manyPrimitiveFieldsTest.WriteDelimitedMessagesToCodedOutputStream_PreAllocatedBuffer(messageCount); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(MessageCountValues))] |
||||
public void ManyPrimitiveFieldsMessage_WriteDelimitedMessagesToSpan(int messageCount) |
||||
{ |
||||
manyPrimitiveFieldsTest.WriteDelimitedMessagesToSpan_PreAllocatedBuffer(messageCount); |
||||
} |
||||
|
||||
private class SubTest |
||||
{ |
||||
private readonly IMessage message; |
||||
private readonly byte[] outputBuffer; |
||||
private readonly byte[] multipleMessagesOutputBuffer; |
||||
|
||||
public SubTest(IMessage message, int maxMessageCount) |
||||
{ |
||||
this.message = message; |
||||
|
||||
int messageSize = message.CalculateSize(); |
||||
this.outputBuffer = new byte[messageSize]; |
||||
this.multipleMessagesOutputBuffer = new byte[maxMessageCount * (messageSize + CodedOutputStream.ComputeLengthSize(messageSize))]; |
||||
} |
||||
|
||||
public byte[] ToByteArray() => message.ToByteArray(); |
||||
|
||||
public byte[] WriteToCodedOutputStream_PreAllocatedBuffer() |
||||
{ |
||||
var cos = new CodedOutputStream(outputBuffer); // use pre-existing output buffer |
||||
message.WriteTo(cos); |
||||
return outputBuffer; |
||||
} |
||||
|
||||
public byte[] WriteToSpan_PreAllocatedBuffer() |
||||
{ |
||||
var span = new Span<byte>(outputBuffer); // use pre-existing output buffer |
||||
message.WriteTo(span); |
||||
return outputBuffer; |
||||
} |
||||
|
||||
public byte[] WriteDelimitedMessagesToCodedOutputStream_PreAllocatedBuffer(int messageCount) |
||||
{ |
||||
var cos = new CodedOutputStream(multipleMessagesOutputBuffer); // use pre-existing output buffer |
||||
for (int i = 0; i < messageCount; i++) |
||||
{ |
||||
cos.WriteMessage(message); |
||||
} |
||||
return multipleMessagesOutputBuffer; |
||||
} |
||||
|
||||
public byte[] WriteDelimitedMessagesToSpan_PreAllocatedBuffer(int messageCount) |
||||
{ |
||||
var span = new Span<byte>(multipleMessagesOutputBuffer); // use pre-existing output buffer |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
for (int i = 0; i < messageCount; i++) |
||||
{ |
||||
ctx.WriteMessage(message); |
||||
} |
||||
return multipleMessagesOutputBuffer; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,467 @@ |
||||
#region Copyright notice and license |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2019 Google Inc. All rights reserved. |
||||
// https://github.com/protocolbuffers/protobuf |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
#endregion |
||||
|
||||
using BenchmarkDotNet.Attributes; |
||||
using System; |
||||
using System.Buffers.Binary; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using System.Buffers; |
||||
using System.Text; |
||||
|
||||
namespace Google.Protobuf.Benchmarks |
||||
{ |
||||
/// <summary> |
||||
/// Benchmarks throughput when writing raw primitives. |
||||
/// </summary> |
||||
[MemoryDiagnoser] |
||||
public class WriteRawPrimitivesBenchmark |
||||
{ |
||||
// key is the encodedSize of varint values |
||||
Dictionary<int, uint[]> varint32Values; |
||||
Dictionary<int, ulong[]> varint64Values; |
||||
|
||||
double[] doubleValues; |
||||
float[] floatValues; |
||||
|
||||
// key is the encodedSize of string values |
||||
Dictionary<int, string[]> stringValues; |
||||
|
||||
// key is the encodedSize of string values |
||||
Dictionary<int, string[]> nonAsciiStringValues; |
||||
|
||||
// key is the encodedSize of string values |
||||
Dictionary<int, ByteString[]> byteStringValues; |
||||
|
||||
// the buffer to which all the data will be written |
||||
byte[] outputBuffer; |
||||
|
||||
Random random = new Random(417384220); // random but deterministic seed |
||||
|
||||
public IEnumerable<int> StringEncodedSizes => new[] { 1, 4, 10, 105, 10080 }; |
||||
|
||||
public IEnumerable<int> NonAsciiStringEncodedSizes => new[] { 4, 10, 105, 10080 }; |
||||
|
||||
[GlobalSetup] |
||||
public void GlobalSetup() |
||||
{ |
||||
outputBuffer = new byte[BytesToWrite]; |
||||
|
||||
varint32Values = new Dictionary<int, uint[]>(); |
||||
varint64Values = new Dictionary<int, ulong[]>(); |
||||
for (int encodedSize = 1; encodedSize <= 10; encodedSize++) |
||||
{ |
||||
if (encodedSize <= 5) |
||||
{ |
||||
varint32Values.Add(encodedSize, CreateRandomVarints32(random, BytesToWrite / encodedSize, encodedSize)); |
||||
} |
||||
varint64Values.Add(encodedSize, CreateRandomVarints64(random, BytesToWrite / encodedSize, encodedSize)); |
||||
} |
||||
|
||||
doubleValues = CreateRandomDoubles(random, BytesToWrite / sizeof(double)); |
||||
floatValues = CreateRandomFloats(random, BytesToWrite / sizeof(float)); |
||||
|
||||
stringValues = new Dictionary<int, string[]>(); |
||||
|
||||
byteStringValues = new Dictionary<int, ByteString[]>(); |
||||
foreach(var encodedSize in StringEncodedSizes) |
||||
{ |
||||
stringValues.Add(encodedSize, CreateStrings(BytesToWrite / encodedSize, encodedSize)); |
||||
byteStringValues.Add(encodedSize, CreateByteStrings(BytesToWrite / encodedSize, encodedSize)); |
||||
} |
||||
|
||||
nonAsciiStringValues = new Dictionary<int, string[]>(); |
||||
foreach(var encodedSize in NonAsciiStringEncodedSizes) |
||||
{ |
||||
nonAsciiStringValues.Add(encodedSize, CreateNonAsciiStrings(BytesToWrite / encodedSize, encodedSize)); |
||||
} |
||||
} |
||||
|
||||
// Total number of bytes that each benchmark will write. |
||||
// Measuring the time taken to write buffer of given size makes it easier to compare parsing speed for different |
||||
// types and makes it easy to calculate the througput (in MB/s) |
||||
// 10800 bytes is chosen because it is divisible by all possible encoded sizes for all primitive types {1..10} |
||||
[Params(10080)] |
||||
public int BytesToWrite { get; set; } |
||||
|
||||
[Benchmark] |
||||
[Arguments(1)] |
||||
[Arguments(2)] |
||||
[Arguments(3)] |
||||
[Arguments(4)] |
||||
[Arguments(5)] |
||||
public void WriteRawVarint32_CodedOutputStream(int encodedSize) |
||||
{ |
||||
var values = varint32Values[encodedSize]; |
||||
var cos = new CodedOutputStream(outputBuffer); |
||||
foreach (var value in values) |
||||
{ |
||||
cos.WriteRawVarint32(value); |
||||
} |
||||
cos.Flush(); |
||||
cos.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[Arguments(1)] |
||||
[Arguments(2)] |
||||
[Arguments(3)] |
||||
[Arguments(4)] |
||||
[Arguments(5)] |
||||
public void WriteRawVarint32_WriteContext(int encodedSize) |
||||
{ |
||||
var values = varint32Values[encodedSize]; |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
foreach (var value in values) |
||||
{ |
||||
ctx.WriteUInt32(value); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[Arguments(1)] |
||||
[Arguments(2)] |
||||
[Arguments(3)] |
||||
[Arguments(4)] |
||||
[Arguments(5)] |
||||
[Arguments(6)] |
||||
[Arguments(7)] |
||||
[Arguments(8)] |
||||
[Arguments(9)] |
||||
[Arguments(10)] |
||||
public void WriteRawVarint64_CodedOutputStream(int encodedSize) |
||||
{ |
||||
var values = varint64Values[encodedSize]; |
||||
var cos = new CodedOutputStream(outputBuffer); |
||||
foreach (var value in values) |
||||
{ |
||||
cos.WriteRawVarint64(value); |
||||
} |
||||
cos.Flush(); |
||||
cos.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[Arguments(1)] |
||||
[Arguments(2)] |
||||
[Arguments(3)] |
||||
[Arguments(4)] |
||||
[Arguments(5)] |
||||
[Arguments(6)] |
||||
[Arguments(7)] |
||||
[Arguments(8)] |
||||
[Arguments(9)] |
||||
[Arguments(10)] |
||||
public void WriteRawVarint64_WriteContext(int encodedSize) |
||||
{ |
||||
var values = varint64Values[encodedSize]; |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
foreach (var value in values) |
||||
{ |
||||
ctx.WriteUInt64(value); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void WriteFixed32_CodedOutputStream() |
||||
{ |
||||
const int encodedSize = sizeof(uint); |
||||
var cos = new CodedOutputStream(outputBuffer); |
||||
for(int i = 0; i < BytesToWrite / encodedSize; i++) |
||||
{ |
||||
cos.WriteFixed32(12345); |
||||
} |
||||
cos.Flush(); |
||||
cos.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void WriteFixed32_WriteContext() |
||||
{ |
||||
const int encodedSize = sizeof(uint); |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
for (uint i = 0; i < BytesToWrite / encodedSize; i++) |
||||
{ |
||||
ctx.WriteFixed32(12345); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void WriteFixed64_CodedOutputStream() |
||||
{ |
||||
const int encodedSize = sizeof(ulong); |
||||
var cos = new CodedOutputStream(outputBuffer); |
||||
for(int i = 0; i < BytesToWrite / encodedSize; i++) |
||||
{ |
||||
cos.WriteFixed64(123456789); |
||||
} |
||||
cos.Flush(); |
||||
cos.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void WriteFixed64_WriteContext() |
||||
{ |
||||
const int encodedSize = sizeof(ulong); |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
for (uint i = 0; i < BytesToWrite / encodedSize; i++) |
||||
{ |
||||
ctx.WriteFixed64(123456789); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void WriteRawFloat_CodedOutputStream() |
||||
{ |
||||
var cos = new CodedOutputStream(outputBuffer); |
||||
foreach (var value in floatValues) |
||||
{ |
||||
cos.WriteFloat(value); |
||||
} |
||||
cos.Flush(); |
||||
cos.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void WriteRawFloat_WriteContext() |
||||
{ |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
foreach (var value in floatValues) |
||||
{ |
||||
ctx.WriteFloat(value); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void WriteRawDouble_CodedOutputStream() |
||||
{ |
||||
var cos = new CodedOutputStream(outputBuffer); |
||||
foreach (var value in doubleValues) |
||||
{ |
||||
cos.WriteDouble(value); |
||||
} |
||||
cos.Flush(); |
||||
cos.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void WriteRawDouble_WriteContext() |
||||
{ |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
foreach (var value in doubleValues) |
||||
{ |
||||
ctx.WriteDouble(value); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(StringEncodedSizes))] |
||||
public void WriteString_CodedOutputStream(int encodedSize) |
||||
{ |
||||
var values = stringValues[encodedSize]; |
||||
var cos = new CodedOutputStream(outputBuffer); |
||||
foreach (var value in values) |
||||
{ |
||||
cos.WriteString(value); |
||||
} |
||||
cos.Flush(); |
||||
cos.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(StringEncodedSizes))] |
||||
public void WriteString_WriteContext(int encodedSize) |
||||
{ |
||||
var values = stringValues[encodedSize]; |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
foreach (var value in values) |
||||
{ |
||||
ctx.WriteString(value); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(NonAsciiStringEncodedSizes))] |
||||
public void WriteNonAsciiString_CodedOutputStream(int encodedSize) |
||||
{ |
||||
var values = nonAsciiStringValues[encodedSize]; |
||||
var cos = new CodedOutputStream(outputBuffer); |
||||
foreach (var value in values) |
||||
{ |
||||
cos.WriteString(value); |
||||
} |
||||
cos.Flush(); |
||||
cos.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(NonAsciiStringEncodedSizes))] |
||||
public void WriteNonAsciiString_WriteContext(int encodedSize) |
||||
{ |
||||
var values = nonAsciiStringValues[encodedSize]; |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
foreach (var value in values) |
||||
{ |
||||
ctx.WriteString(value); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(StringEncodedSizes))] |
||||
public void WriteBytes_CodedOutputStream(int encodedSize) |
||||
{ |
||||
var values = byteStringValues[encodedSize]; |
||||
var cos = new CodedOutputStream(outputBuffer); |
||||
foreach (var value in values) |
||||
{ |
||||
cos.WriteBytes(value); |
||||
} |
||||
cos.Flush(); |
||||
cos.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(StringEncodedSizes))] |
||||
public void WriteBytes_WriteContext(int encodedSize) |
||||
{ |
||||
var values = byteStringValues[encodedSize]; |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
foreach (var value in values) |
||||
{ |
||||
ctx.WriteBytes(value); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
private static uint[] CreateRandomVarints32(Random random, int valueCount, int encodedSize) |
||||
{ |
||||
var result = new uint[valueCount]; |
||||
for (int i = 0; i < valueCount; i++) |
||||
{ |
||||
result[i] = (uint) ParseRawPrimitivesBenchmark.RandomUnsignedVarint(random, encodedSize, true); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
private static ulong[] CreateRandomVarints64(Random random, int valueCount, int encodedSize) |
||||
{ |
||||
var result = new ulong[valueCount]; |
||||
for (int i = 0; i < valueCount; i++) |
||||
{ |
||||
result[i] = ParseRawPrimitivesBenchmark.RandomUnsignedVarint(random, encodedSize, false); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
private static float[] CreateRandomFloats(Random random, int valueCount) |
||||
{ |
||||
var result = new float[valueCount]; |
||||
for (int i = 0; i < valueCount; i++) |
||||
{ |
||||
result[i] = (float)random.NextDouble(); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
private static double[] CreateRandomDoubles(Random random, int valueCount) |
||||
{ |
||||
var result = new double[valueCount]; |
||||
for (int i = 0; i < valueCount; i++) |
||||
{ |
||||
result[i] = random.NextDouble(); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
private static string[] CreateStrings(int valueCount, int encodedSize) |
||||
{ |
||||
var str = ParseRawPrimitivesBenchmark.CreateStringWithEncodedSize(encodedSize); |
||||
|
||||
var result = new string[valueCount]; |
||||
for (int i = 0; i < valueCount; i++) |
||||
{ |
||||
result[i] = str; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
private static string[] CreateNonAsciiStrings(int valueCount, int encodedSize) |
||||
{ |
||||
var str = ParseRawPrimitivesBenchmark.CreateNonAsciiStringWithEncodedSize(encodedSize); |
||||
|
||||
var result = new string[valueCount]; |
||||
for (int i = 0; i < valueCount; i++) |
||||
{ |
||||
result[i] = str; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
private static ByteString[] CreateByteStrings(int valueCount, int encodedSize) |
||||
{ |
||||
var str = ParseRawPrimitivesBenchmark.CreateStringWithEncodedSize(encodedSize); |
||||
|
||||
var result = new ByteString[valueCount]; |
||||
for (int i = 0; i < valueCount; i++) |
||||
{ |
||||
result[i] = ByteString.CopyFrom(Encoding.UTF8.GetBytes(str)); |
||||
} |
||||
return result; |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue