commit
1595417dd3
598 changed files with 7647 additions and 22808 deletions
@ -1,5 +1,4 @@ |
||||
# These are fetched as external repositories. |
||||
third_party/abseil-cpp |
||||
third_party/benchmark |
||||
third_party/googletest |
||||
_build/ |
||||
|
@ -1,12 +1,8 @@ |
||||
[submodule "third_party/benchmark"] |
||||
path = third_party/benchmark |
||||
url = https://github.com/google/benchmark.git |
||||
ignore = dirty |
||||
[submodule "third_party/googletest"] |
||||
path = third_party/googletest |
||||
url = https://github.com/google/googletest.git |
||||
ignore = dirty |
||||
[submodule "third_party/abseil-cpp"] |
||||
path = third_party/abseil-cpp |
||||
url = https://github.com/abseil/abseil-cpp |
||||
url = https://github.com/abseil/abseil-cpp.git |
||||
branch = lts_2022_06_23 |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,325 +0,0 @@ |
||||
// <auto-generated> |
||||
// Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
// source: benchmarks.proto |
||||
// </auto-generated> |
||||
#pragma warning disable 1591, 0612, 3021, 8981 |
||||
#region Designer generated code |
||||
|
||||
using pb = global::Google.Protobuf; |
||||
using pbc = global::Google.Protobuf.Collections; |
||||
using pbr = global::Google.Protobuf.Reflection; |
||||
using scg = global::System.Collections.Generic; |
||||
namespace Benchmarks { |
||||
|
||||
/// <summary>Holder for reflection information generated from benchmarks.proto</summary> |
||||
public static partial class BenchmarksReflection { |
||||
|
||||
#region Descriptor |
||||
/// <summary>File descriptor for benchmarks.proto</summary> |
||||
public static pbr::FileDescriptor Descriptor { |
||||
get { return descriptor; } |
||||
} |
||||
private static pbr::FileDescriptor descriptor; |
||||
|
||||
static BenchmarksReflection() { |
||||
byte[] descriptorData = global::System.Convert.FromBase64String( |
||||
string.Concat( |
||||
"ChBiZW5jaG1hcmtzLnByb3RvEgpiZW5jaG1hcmtzIkcKEEJlbmNobWFya0Rh", |
||||
"dGFzZXQSDAoEbmFtZRgBIAEoCRIUCgxtZXNzYWdlX25hbWUYAiABKAkSDwoH", |
||||
"cGF5bG9hZBgDIAMoDEIgCh5jb20uZ29vZ2xlLnByb3RvYnVmLmJlbmNobWFy", |
||||
"a3NiBnByb3RvMw==")); |
||||
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, |
||||
new pbr::FileDescriptor[] { }, |
||||
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { |
||||
new pbr::GeneratedClrTypeInfo(typeof(global::Benchmarks.BenchmarkDataset), global::Benchmarks.BenchmarkDataset.Parser, new[]{ "Name", "MessageName", "Payload" }, null, null, null, null) |
||||
})); |
||||
} |
||||
#endregion |
||||
|
||||
} |
||||
#region Messages |
||||
public sealed partial class BenchmarkDataset : pb::IMessage<BenchmarkDataset> |
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE |
||||
, pb::IBufferMessage |
||||
#endif |
||||
{ |
||||
private static readonly pb::MessageParser<BenchmarkDataset> _parser = new pb::MessageParser<BenchmarkDataset>(() => new BenchmarkDataset()); |
||||
private pb::UnknownFieldSet _unknownFields; |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public static pb::MessageParser<BenchmarkDataset> Parser { get { return _parser; } } |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Benchmarks.BenchmarksReflection.Descriptor.MessageTypes[0]; } |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public BenchmarkDataset() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public BenchmarkDataset(BenchmarkDataset other) : this() { |
||||
name_ = other.name_; |
||||
messageName_ = other.messageName_; |
||||
payload_ = other.payload_.Clone(); |
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public BenchmarkDataset Clone() { |
||||
return new BenchmarkDataset(this); |
||||
} |
||||
|
||||
/// <summary>Field number for the "name" field.</summary> |
||||
public const int NameFieldNumber = 1; |
||||
private string name_ = ""; |
||||
/// <summary> |
||||
/// Name of the benchmark dataset. This should be unique across all datasets. |
||||
/// Should only contain word characters: [a-zA-Z0-9_] |
||||
/// </summary> |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public string Name { |
||||
get { return name_; } |
||||
set { |
||||
name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); |
||||
} |
||||
} |
||||
|
||||
/// <summary>Field number for the "message_name" field.</summary> |
||||
public const int MessageNameFieldNumber = 2; |
||||
private string messageName_ = ""; |
||||
/// <summary> |
||||
/// Fully-qualified name of the protobuf message for this dataset. |
||||
/// It will be one of the messages defined benchmark_messages_proto2.proto |
||||
/// or benchmark_messages_proto3.proto. |
||||
/// |
||||
/// Implementations that do not support reflection can implement this with |
||||
/// an explicit "if/else" chain that lists every known message defined |
||||
/// in those files. |
||||
/// </summary> |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public string MessageName { |
||||
get { return messageName_; } |
||||
set { |
||||
messageName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); |
||||
} |
||||
} |
||||
|
||||
/// <summary>Field number for the "payload" field.</summary> |
||||
public const int PayloadFieldNumber = 3; |
||||
private static readonly pb::FieldCodec<pb::ByteString> _repeated_payload_codec |
||||
= pb::FieldCodec.ForBytes(26); |
||||
private readonly pbc::RepeatedField<pb::ByteString> payload_ = new pbc::RepeatedField<pb::ByteString>(); |
||||
/// <summary> |
||||
/// The payload(s) for this dataset. They should be parsed or serialized |
||||
/// in sequence, in a loop, ie. |
||||
/// |
||||
/// while (!benchmarkDone) { // Benchmark runner decides when to exit. |
||||
/// for (i = 0; i < benchmark.payload.length; i++) { |
||||
/// parse(benchmark.payload[i]) |
||||
/// } |
||||
/// } |
||||
/// |
||||
/// This is intended to let datasets include a variety of data to provide |
||||
/// potentially more realistic results than just parsing the same message |
||||
/// over and over. A single message parsed repeatedly could yield unusually |
||||
/// good branch prediction performance. |
||||
/// </summary> |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public pbc::RepeatedField<pb::ByteString> Payload { |
||||
get { return payload_; } |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public override bool Equals(object other) { |
||||
return Equals(other as BenchmarkDataset); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public bool Equals(BenchmarkDataset other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
if (Name != other.Name) return false; |
||||
if (MessageName != other.MessageName) return false; |
||||
if(!payload_.Equals(other.payload_)) return false; |
||||
return Equals(_unknownFields, other._unknownFields); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
if (Name.Length != 0) hash ^= Name.GetHashCode(); |
||||
if (MessageName.Length != 0) hash ^= MessageName.GetHashCode(); |
||||
hash ^= payload_.GetHashCode(); |
||||
if (_unknownFields != null) { |
||||
hash ^= _unknownFields.GetHashCode(); |
||||
} |
||||
return hash; |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public override string ToString() { |
||||
return pb::JsonFormatter.ToDiagnosticString(this); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE |
||||
output.WriteRawMessage(this); |
||||
#else |
||||
if (Name.Length != 0) { |
||||
output.WriteRawTag(10); |
||||
output.WriteString(Name); |
||||
} |
||||
if (MessageName.Length != 0) { |
||||
output.WriteRawTag(18); |
||||
output.WriteString(MessageName); |
||||
} |
||||
payload_.WriteTo(output, _repeated_payload_codec); |
||||
if (_unknownFields != null) { |
||||
_unknownFields.WriteTo(output); |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { |
||||
if (Name.Length != 0) { |
||||
output.WriteRawTag(10); |
||||
output.WriteString(Name); |
||||
} |
||||
if (MessageName.Length != 0) { |
||||
output.WriteRawTag(18); |
||||
output.WriteString(MessageName); |
||||
} |
||||
payload_.WriteTo(ref output, _repeated_payload_codec); |
||||
if (_unknownFields != null) { |
||||
_unknownFields.WriteTo(ref output); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
if (Name.Length != 0) { |
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); |
||||
} |
||||
if (MessageName.Length != 0) { |
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(MessageName); |
||||
} |
||||
size += payload_.CalculateSize(_repeated_payload_codec); |
||||
if (_unknownFields != null) { |
||||
size += _unknownFields.CalculateSize(); |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public void MergeFrom(BenchmarkDataset other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
if (other.Name.Length != 0) { |
||||
Name = other.Name; |
||||
} |
||||
if (other.MessageName.Length != 0) { |
||||
MessageName = other.MessageName; |
||||
} |
||||
payload_.Add(other.payload_); |
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE |
||||
input.ReadRawMessage(this); |
||||
#else |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); |
||||
break; |
||||
case 10: { |
||||
Name = input.ReadString(); |
||||
break; |
||||
} |
||||
case 18: { |
||||
MessageName = input.ReadString(); |
||||
break; |
||||
} |
||||
case 26: { |
||||
payload_.AddEntriesFrom(input, _repeated_payload_codec); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] |
||||
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); |
||||
break; |
||||
case 10: { |
||||
Name = input.ReadString(); |
||||
break; |
||||
} |
||||
case 18: { |
||||
MessageName = input.ReadString(); |
||||
break; |
||||
} |
||||
case 26: { |
||||
payload_.AddEntriesFrom(ref input, _repeated_payload_codec); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
} |
||||
|
||||
#endregion |
||||
|
||||
} |
||||
|
||||
#endregion Designer generated code |
@ -1,72 +0,0 @@ |
||||
#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; |
||||
|
||||
namespace Google.Protobuf.Benchmarks |
||||
{ |
||||
/// <summary> |
||||
/// Benchmarks using ByteString. |
||||
/// </summary> |
||||
[MemoryDiagnoser] |
||||
public class ByteStringBenchmark |
||||
{ |
||||
private const int Zero = 0; |
||||
private const int Kilobyte = 1024; |
||||
private const int _128Kilobytes = 1024 * 128; |
||||
private const int Megabyte = 1024 * 1024; |
||||
private const int _10Megabytes = 1024 * 1024 * 10; |
||||
|
||||
byte[] byteBuffer; |
||||
|
||||
[GlobalSetup] |
||||
public void GlobalSetup() |
||||
{ |
||||
byteBuffer = new byte[PayloadSize]; |
||||
} |
||||
|
||||
[Params(Zero, Kilobyte, _128Kilobytes, Megabyte, _10Megabytes)] |
||||
public int PayloadSize { get; set; } |
||||
|
||||
[Benchmark] |
||||
public ByteString CopyFrom() |
||||
{ |
||||
return ByteString.CopyFrom(byteBuffer); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public ByteString UnsafeWrap() |
||||
{ |
||||
return UnsafeByteOperations.UnsafeWrap(byteBuffer); |
||||
} |
||||
} |
||||
} |
@ -1,258 +0,0 @@ |
||||
#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; |
||||
using Benchmarks.Proto3; |
||||
|
||||
namespace Google.Protobuf.Benchmarks |
||||
{ |
||||
/// <summary> |
||||
/// Benchmark that tests parsing performance for various messages. |
||||
/// </summary> |
||||
[MemoryDiagnoser] |
||||
public class ParseMessagesBenchmark |
||||
{ |
||||
const int MaxMessages = 100; |
||||
|
||||
private readonly SubTest manyWrapperFieldsTest = new(CreateManyWrapperFieldsMessage(), ManyWrapperFieldsMessage.Parser, () => new ManyWrapperFieldsMessage(), MaxMessages); |
||||
private readonly SubTest manyPrimitiveFieldsTest = new(CreateManyPrimitiveFieldsMessage(), ManyPrimitiveFieldsMessage.Parser, () => new ManyPrimitiveFieldsMessage(), MaxMessages); |
||||
private readonly SubTest repeatedFieldTest = new(CreateRepeatedFieldMessage(), GoogleMessage1.Parser, () => new GoogleMessage1(), MaxMessages); |
||||
private readonly SubTest emptyMessageTest = new(new Empty(), Empty.Parser, () => new Empty(), MaxMessages); |
||||
|
||||
public IEnumerable<int> MessageCountValues => new[] { 10, 100 }; |
||||
|
||||
[GlobalSetup] |
||||
public void GlobalSetup() |
||||
{ |
||||
} |
||||
|
||||
[Benchmark] |
||||
public IMessage ManyWrapperFieldsMessage_ParseFromByteArray() |
||||
{ |
||||
return manyWrapperFieldsTest.ParseFromByteArray(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public IMessage ManyWrapperFieldsMessage_ParseFromReadOnlySequence() |
||||
{ |
||||
return manyWrapperFieldsTest.ParseFromReadOnlySequence(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public IMessage ManyPrimitiveFieldsMessage_ParseFromByteArray() |
||||
{ |
||||
return manyPrimitiveFieldsTest.ParseFromByteArray(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public IMessage ManyPrimitiveFieldsMessage_ParseFromReadOnlySequence() |
||||
{ |
||||
return manyPrimitiveFieldsTest.ParseFromReadOnlySequence(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public IMessage RepeatedFieldMessage_ParseFromByteArray() |
||||
{ |
||||
return repeatedFieldTest.ParseFromByteArray(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public IMessage RepeatedFieldMessage_ParseFromReadOnlySequence() |
||||
{ |
||||
return repeatedFieldTest.ParseFromReadOnlySequence(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public IMessage EmptyMessage_ParseFromByteArray() |
||||
{ |
||||
return emptyMessageTest.ParseFromByteArray(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public IMessage EmptyMessage_ParseFromReadOnlySequence() |
||||
{ |
||||
return emptyMessageTest.ParseFromReadOnlySequence(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(MessageCountValues))] |
||||
public void ManyWrapperFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount) |
||||
{ |
||||
manyWrapperFieldsTest.ParseDelimitedMessagesFromByteArray(messageCount); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(MessageCountValues))] |
||||
public void ManyWrapperFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount) |
||||
{ |
||||
manyWrapperFieldsTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(MessageCountValues))] |
||||
public void ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount) |
||||
{ |
||||
manyPrimitiveFieldsTest.ParseDelimitedMessagesFromByteArray(messageCount); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(MessageCountValues))] |
||||
public void ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount) |
||||
{ |
||||
manyPrimitiveFieldsTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(MessageCountValues))] |
||||
public void RepeatedFieldMessage_ParseDelimitedMessagesFromByteArray(int messageCount) |
||||
{ |
||||
repeatedFieldTest.ParseDelimitedMessagesFromByteArray(messageCount); |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(MessageCountValues))] |
||||
public void RepeatedFieldMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount) |
||||
{ |
||||
repeatedFieldTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount); |
||||
} |
||||
|
||||
public static ManyWrapperFieldsMessage CreateManyWrapperFieldsMessage() |
||||
{ |
||||
// Example data match data of an internal benchmarks |
||||
return new ManyWrapperFieldsMessage() |
||||
{ |
||||
Int64Field19 = 123, |
||||
Int64Field37 = 1000032, |
||||
Int64Field26 = 3453524500, |
||||
DoubleField79 = 1.2, |
||||
DoubleField25 = 234, |
||||
DoubleField9 = 123.3, |
||||
DoubleField28 = 23, |
||||
DoubleField7 = 234, |
||||
DoubleField50 = 2.45 |
||||
}; |
||||
} |
||||
|
||||
public static ManyPrimitiveFieldsMessage CreateManyPrimitiveFieldsMessage() |
||||
{ |
||||
// Example data match data of an internal benchmarks |
||||
return new ManyPrimitiveFieldsMessage() |
||||
{ |
||||
Int64Field19 = 123, |
||||
Int64Field37 = 1000032, |
||||
Int64Field26 = 3453524500, |
||||
DoubleField79 = 1.2, |
||||
DoubleField25 = 234, |
||||
DoubleField9 = 123.3, |
||||
DoubleField28 = 23, |
||||
DoubleField7 = 234, |
||||
DoubleField50 = 2.45 |
||||
}; |
||||
} |
||||
|
||||
public static GoogleMessage1 CreateRepeatedFieldMessage() |
||||
{ |
||||
// Message with a repeated fixed length item collection |
||||
var message = new GoogleMessage1(); |
||||
for (ulong i = 0; i < 1000; i++) |
||||
{ |
||||
message.Field5.Add(i); |
||||
} |
||||
return message; |
||||
} |
||||
|
||||
private class SubTest |
||||
{ |
||||
private readonly IMessage message; |
||||
private readonly MessageParser parser; |
||||
private readonly Func<IMessage> factory; |
||||
private readonly byte[] data; |
||||
private readonly byte[] multipleMessagesData; |
||||
|
||||
private readonly ReadOnlySequence<byte> dataSequence; |
||||
private readonly ReadOnlySequence<byte> multipleMessagesDataSequence; |
||||
|
||||
public SubTest(IMessage message, MessageParser parser, Func<IMessage> factory, int maxMessageCount) |
||||
{ |
||||
this.message = message; |
||||
this.parser = parser; |
||||
this.factory = factory; |
||||
this.data = message.ToByteArray(); |
||||
this.multipleMessagesData = CreateBufferWithMultipleMessages(message, maxMessageCount); |
||||
this.dataSequence = new ReadOnlySequence<byte>(this.data); |
||||
this.multipleMessagesDataSequence = new ReadOnlySequence<byte>(this.multipleMessagesData); |
||||
} |
||||
|
||||
public IMessage ParseFromByteArray() => parser.ParseFrom(data); |
||||
|
||||
public IMessage ParseFromReadOnlySequence() => parser.ParseFrom(dataSequence); |
||||
|
||||
public void ParseDelimitedMessagesFromByteArray(int messageCount) |
||||
{ |
||||
var input = new CodedInputStream(multipleMessagesData); |
||||
for (int i = 0; i < messageCount; i++) |
||||
{ |
||||
var msg = factory(); |
||||
input.ReadMessage(msg); |
||||
} |
||||
} |
||||
|
||||
public void ParseDelimitedMessagesFromReadOnlySequence(int messageCount) |
||||
{ |
||||
ParseContext.Initialize(multipleMessagesDataSequence, out ParseContext ctx); |
||||
for (int i = 0; i < messageCount; i++) |
||||
{ |
||||
var msg = factory(); |
||||
ctx.ReadMessage(msg); |
||||
} |
||||
} |
||||
|
||||
private static byte[] CreateBufferWithMultipleMessages(IMessage msg, int msgCount) |
||||
{ |
||||
var ms = new MemoryStream(); |
||||
var cos = new CodedOutputStream(ms); |
||||
for (int i = 0; i < msgCount; i++) |
||||
{ |
||||
cos.WriteMessage(msg); |
||||
} |
||||
cos.Flush(); |
||||
return ms.ToArray(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,536 +0,0 @@ |
||||
#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; |
||||
|
||||
namespace Google.Protobuf.Benchmarks |
||||
{ |
||||
/// <summary> |
||||
/// Benchmarks throughput when parsing raw primitives. |
||||
/// </summary> |
||||
[MemoryDiagnoser] |
||||
public class ParseRawPrimitivesBenchmark |
||||
{ |
||||
// key is the encodedSize of varint values |
||||
Dictionary<int, byte[]> varintInputBuffers; |
||||
|
||||
byte[] doubleInputBuffer; |
||||
byte[] floatInputBuffer; |
||||
byte[] fixedIntInputBuffer; |
||||
|
||||
// key is the encodedSize of string values |
||||
Dictionary<int, byte[]> stringInputBuffers; |
||||
Dictionary<int, ReadOnlySequence<byte>> stringInputBuffersSegmented; |
||||
|
||||
Random random = new Random(417384220); // random but deterministic seed |
||||
|
||||
public IEnumerable<int> StringEncodedSizes => new[] { 1, 4, 10, 105, 10080 }; |
||||
public IEnumerable<int> StringSegmentedEncodedSizes => new[] { 105, 10080 }; |
||||
|
||||
[GlobalSetup] |
||||
public void GlobalSetup() |
||||
{ |
||||
// add some extra values that we won't read just to make sure we are far enough from the end of the buffer |
||||
// which allows the parser fastpath to always kick in. |
||||
const int paddingValueCount = 100; |
||||
|
||||
varintInputBuffers = new Dictionary<int, byte[]>(); |
||||
for (int encodedSize = 1; encodedSize <= 10; encodedSize++) |
||||
{ |
||||
byte[] buffer = CreateBufferWithRandomVarints(random, BytesToParse / encodedSize, encodedSize, paddingValueCount); |
||||
varintInputBuffers.Add(encodedSize, buffer); |
||||
} |
||||
|
||||
doubleInputBuffer = CreateBufferWithRandomDoubles(random, BytesToParse / sizeof(double), paddingValueCount); |
||||
floatInputBuffer = CreateBufferWithRandomFloats(random, BytesToParse / sizeof(float), paddingValueCount); |
||||
fixedIntInputBuffer = CreateBufferWithRandomData(random, BytesToParse / sizeof(long), sizeof(long), paddingValueCount); |
||||
|
||||
stringInputBuffers = new Dictionary<int, byte[]>(); |
||||
foreach (var encodedSize in StringEncodedSizes) |
||||
{ |
||||
byte[] buffer = CreateBufferWithStrings(BytesToParse / encodedSize, encodedSize, encodedSize < 10 ? 10 : 1 ); |
||||
stringInputBuffers.Add(encodedSize, buffer); |
||||
} |
||||
|
||||
stringInputBuffersSegmented = new Dictionary<int, ReadOnlySequence<byte>>(); |
||||
foreach (var encodedSize in StringSegmentedEncodedSizes) |
||||
{ |
||||
byte[] buffer = CreateBufferWithStrings(BytesToParse / encodedSize, encodedSize, encodedSize < 10 ? 10 : 1); |
||||
stringInputBuffersSegmented.Add(encodedSize, ReadOnlySequenceFactory.CreateWithContent(buffer, segmentSize: 128, addEmptySegmentDelimiters: false)); |
||||
} |
||||
} |
||||
|
||||
// Total number of bytes that each benchmark will parse. |
||||
// Measuring the time taken to parse 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 BytesToParse { get; set; } |
||||
|
||||
[Benchmark] |
||||
[Arguments(1)] |
||||
[Arguments(2)] |
||||
[Arguments(3)] |
||||
[Arguments(4)] |
||||
[Arguments(5)] |
||||
public int ParseRawVarint32_CodedInputStream(int encodedSize) |
||||
{ |
||||
CodedInputStream cis = new CodedInputStream(varintInputBuffers[encodedSize]); |
||||
int sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += cis.ReadInt32(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
[Arguments(1)] |
||||
[Arguments(2)] |
||||
[Arguments(3)] |
||||
[Arguments(4)] |
||||
[Arguments(5)] |
||||
public int ParseRawVarint32_ParseContext(int encodedSize) |
||||
{ |
||||
InitializeParseContext(varintInputBuffers[encodedSize], out ParseContext ctx); |
||||
int sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += ctx.ReadInt32(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
[Arguments(1)] |
||||
[Arguments(2)] |
||||
[Arguments(3)] |
||||
[Arguments(4)] |
||||
[Arguments(5)] |
||||
[Arguments(6)] |
||||
[Arguments(7)] |
||||
[Arguments(8)] |
||||
[Arguments(9)] |
||||
[Arguments(10)] |
||||
public long ParseRawVarint64_CodedInputStream(int encodedSize) |
||||
{ |
||||
CodedInputStream cis = new CodedInputStream(varintInputBuffers[encodedSize]); |
||||
long sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += cis.ReadInt64(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
[Arguments(1)] |
||||
[Arguments(2)] |
||||
[Arguments(3)] |
||||
[Arguments(4)] |
||||
[Arguments(5)] |
||||
[Arguments(6)] |
||||
[Arguments(7)] |
||||
[Arguments(8)] |
||||
[Arguments(9)] |
||||
[Arguments(10)] |
||||
public long ParseRawVarint64_ParseContext(int encodedSize) |
||||
{ |
||||
InitializeParseContext(varintInputBuffers[encodedSize], out ParseContext ctx); |
||||
long sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += ctx.ReadInt64(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
public uint ParseFixed32_CodedInputStream() |
||||
{ |
||||
const int encodedSize = sizeof(uint); |
||||
CodedInputStream cis = new CodedInputStream(fixedIntInputBuffer); |
||||
uint sum = 0; |
||||
for (uint i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += cis.ReadFixed32(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
public uint ParseFixed32_ParseContext() |
||||
{ |
||||
const int encodedSize = sizeof(uint); |
||||
InitializeParseContext(fixedIntInputBuffer, out ParseContext ctx); |
||||
uint sum = 0; |
||||
for (uint i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += ctx.ReadFixed32(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
public ulong ParseFixed64_CodedInputStream() |
||||
{ |
||||
const int encodedSize = sizeof(ulong); |
||||
CodedInputStream cis = new CodedInputStream(fixedIntInputBuffer); |
||||
ulong sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += cis.ReadFixed64(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
public ulong ParseFixed64_ParseContext() |
||||
{ |
||||
const int encodedSize = sizeof(ulong); |
||||
InitializeParseContext(fixedIntInputBuffer, out ParseContext ctx); |
||||
ulong sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += ctx.ReadFixed64(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
public float ParseRawFloat_CodedInputStream() |
||||
{ |
||||
const int encodedSize = sizeof(float); |
||||
CodedInputStream cis = new CodedInputStream(floatInputBuffer); |
||||
float sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += cis.ReadFloat(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
public float ParseRawFloat_ParseContext() |
||||
{ |
||||
const int encodedSize = sizeof(float); |
||||
InitializeParseContext(floatInputBuffer, out ParseContext ctx); |
||||
float sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += ctx.ReadFloat(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
public double ParseRawDouble_CodedInputStream() |
||||
{ |
||||
const int encodedSize = sizeof(double); |
||||
CodedInputStream cis = new CodedInputStream(doubleInputBuffer); |
||||
double sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += cis.ReadDouble(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
public double ParseRawDouble_ParseContext() |
||||
{ |
||||
const int encodedSize = sizeof(double); |
||||
InitializeParseContext(doubleInputBuffer, out ParseContext ctx); |
||||
double sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += ctx.ReadDouble(); |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(StringEncodedSizes))] |
||||
public int ParseString_CodedInputStream(int encodedSize) |
||||
{ |
||||
CodedInputStream cis = new CodedInputStream(stringInputBuffers[encodedSize]); |
||||
int sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += cis.ReadString().Length; |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(StringEncodedSizes))] |
||||
public int ParseString_ParseContext(int encodedSize) |
||||
{ |
||||
InitializeParseContext(stringInputBuffers[encodedSize], out ParseContext ctx); |
||||
int sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += ctx.ReadString().Length; |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(StringSegmentedEncodedSizes))] |
||||
public int ParseString_ParseContext_MultipleSegments(int encodedSize) |
||||
{ |
||||
InitializeParseContext(stringInputBuffersSegmented[encodedSize], out ParseContext ctx); |
||||
int sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += ctx.ReadString().Length; |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(StringEncodedSizes))] |
||||
public int ParseBytes_CodedInputStream(int encodedSize) |
||||
{ |
||||
CodedInputStream cis = new CodedInputStream(stringInputBuffers[encodedSize]); |
||||
int sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += cis.ReadBytes().Length; |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(StringEncodedSizes))] |
||||
public int ParseBytes_ParseContext(int encodedSize) |
||||
{ |
||||
InitializeParseContext(stringInputBuffers[encodedSize], out ParseContext ctx); |
||||
int sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += ctx.ReadBytes().Length; |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
[Benchmark] |
||||
[ArgumentsSource(nameof(StringSegmentedEncodedSizes))] |
||||
public int ParseBytes_ParseContext_MultipleSegments(int encodedSize) |
||||
{ |
||||
InitializeParseContext(stringInputBuffersSegmented[encodedSize], out ParseContext ctx); |
||||
int sum = 0; |
||||
for (int i = 0; i < BytesToParse / encodedSize; i++) |
||||
{ |
||||
sum += ctx.ReadBytes().Length; |
||||
} |
||||
return sum; |
||||
} |
||||
|
||||
private static void InitializeParseContext(byte[] buffer, out ParseContext ctx) |
||||
{ |
||||
ParseContext.Initialize(new ReadOnlySequence<byte>(buffer), out ctx); |
||||
} |
||||
|
||||
private static void InitializeParseContext(ReadOnlySequence<byte> buffer, out ParseContext ctx) |
||||
{ |
||||
ParseContext.Initialize(buffer, out ctx); |
||||
} |
||||
|
||||
private static byte[] CreateBufferWithRandomVarints(Random random, int valueCount, int encodedSize, int paddingValueCount) |
||||
{ |
||||
MemoryStream ms = new MemoryStream(); |
||||
CodedOutputStream cos = new CodedOutputStream(ms); |
||||
for (int i = 0; i < valueCount + paddingValueCount; i++) |
||||
{ |
||||
cos.WriteUInt64(RandomUnsignedVarint(random, encodedSize, false)); |
||||
} |
||||
cos.Flush(); |
||||
var buffer = ms.ToArray(); |
||||
|
||||
if (buffer.Length != encodedSize * (valueCount + paddingValueCount)) |
||||
{ |
||||
throw new InvalidOperationException($"Unexpected output buffer length {buffer.Length}"); |
||||
} |
||||
return buffer; |
||||
} |
||||
|
||||
private static byte[] CreateBufferWithRandomFloats(Random random, int valueCount, int paddingValueCount) |
||||
{ |
||||
MemoryStream ms = new MemoryStream(); |
||||
CodedOutputStream cos = new CodedOutputStream(ms); |
||||
for (int i = 0; i < valueCount + paddingValueCount; i++) |
||||
{ |
||||
cos.WriteFloat((float)random.NextDouble()); |
||||
} |
||||
cos.Flush(); |
||||
var buffer = ms.ToArray(); |
||||
return buffer; |
||||
} |
||||
|
||||
private static byte[] CreateBufferWithRandomDoubles(Random random, int valueCount, int paddingValueCount) |
||||
{ |
||||
MemoryStream ms = new MemoryStream(); |
||||
CodedOutputStream cos = new CodedOutputStream(ms); |
||||
for (int i = 0; i < valueCount + paddingValueCount; i++) |
||||
{ |
||||
cos.WriteDouble(random.NextDouble()); |
||||
} |
||||
cos.Flush(); |
||||
var buffer = ms.ToArray(); |
||||
return buffer; |
||||
} |
||||
|
||||
private static byte[] CreateBufferWithRandomData(Random random, int valueCount, int encodedSize, int paddingValueCount) |
||||
{ |
||||
int bufferSize = (valueCount + paddingValueCount) * encodedSize; |
||||
var buffer = new byte[bufferSize]; |
||||
random.NextBytes(buffer); |
||||
return buffer; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Generate a random value that will take exactly "encodedSize" bytes when varint-encoded. |
||||
/// </summary> |
||||
public static ulong RandomUnsignedVarint(Random random, int encodedSize, bool fitsIn32Bits) |
||||
{ |
||||
Span<byte> randomBytesBuffer = stackalloc byte[8]; |
||||
|
||||
if (encodedSize < 1 || encodedSize > 10 || (fitsIn32Bits && encodedSize > 5)) |
||||
{ |
||||
throw new ArgumentException("Illegal encodedSize value requested", nameof(encodedSize)); |
||||
} |
||||
const int bitsPerByte = 7; |
||||
|
||||
ulong result = 0; |
||||
while (true) |
||||
{ |
||||
random.NextBytes(randomBytesBuffer); |
||||
ulong randomValue = BinaryPrimitives.ReadUInt64LittleEndian(randomBytesBuffer); |
||||
|
||||
// only use the number of random bits we need |
||||
ulong bitmask = encodedSize < 10 ? ((1UL << (encodedSize * bitsPerByte)) - 1) : ulong.MaxValue; |
||||
result = randomValue & bitmask; |
||||
|
||||
if (fitsIn32Bits) |
||||
{ |
||||
// make sure the resulting value is representable by a uint. |
||||
result &= uint.MaxValue; |
||||
} |
||||
|
||||
if (encodedSize == 10) |
||||
{ |
||||
// for 10-byte values the highest bit always needs to be set (7*9=63) |
||||
result |= ulong.MaxValue; |
||||
break; |
||||
} |
||||
|
||||
// some random values won't require the full "encodedSize" bytes, check that at least |
||||
// one of the top 7 bits is set. Retrying is fine since it only happens rarely |
||||
if (encodedSize == 1 || (result & (0x7FUL << ((encodedSize - 1) * bitsPerByte))) != 0) |
||||
{ |
||||
break; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
private static byte[] CreateBufferWithStrings(int valueCount, int encodedSize, int paddingValueCount) |
||||
{ |
||||
var str = CreateStringWithEncodedSize(encodedSize); |
||||
|
||||
MemoryStream ms = new MemoryStream(); |
||||
CodedOutputStream cos = new CodedOutputStream(ms); |
||||
for (int i = 0; i < valueCount + paddingValueCount; i++) |
||||
{ |
||||
cos.WriteString(str); |
||||
} |
||||
cos.Flush(); |
||||
var buffer = ms.ToArray(); |
||||
|
||||
if (buffer.Length != encodedSize * (valueCount + paddingValueCount)) |
||||
{ |
||||
throw new InvalidOperationException($"Unexpected output buffer length {buffer.Length}"); |
||||
} |
||||
return buffer; |
||||
} |
||||
|
||||
public static string CreateStringWithEncodedSize(int encodedSize) |
||||
{ |
||||
var str = new string('a', encodedSize); |
||||
while (CodedOutputStream.ComputeStringSize(str) > encodedSize) |
||||
{ |
||||
str = str.Substring(1); |
||||
} |
||||
|
||||
if (CodedOutputStream.ComputeStringSize(str) != encodedSize) |
||||
{ |
||||
throw new InvalidOperationException($"Generated string with wrong encodedSize"); |
||||
} |
||||
return str; |
||||
} |
||||
|
||||
public static string CreateNonAsciiStringWithEncodedSize(int encodedSize) |
||||
{ |
||||
if (encodedSize < 3) |
||||
{ |
||||
throw new ArgumentException("Illegal encoded size for a string with non-ascii chars."); |
||||
} |
||||
var twoByteChar = '\u00DC'; // U-umlaut, UTF8 encoding has 2 bytes |
||||
var str = new string(twoByteChar, encodedSize / 2); |
||||
while (CodedOutputStream.ComputeStringSize(str) > encodedSize) |
||||
{ |
||||
str = str.Substring(1); |
||||
} |
||||
|
||||
// add padding of ascii characters to reach the desired encoded size. |
||||
while (CodedOutputStream.ComputeStringSize(str) < encodedSize) |
||||
{ |
||||
str += 'a'; |
||||
} |
||||
|
||||
// Note that for a few specific encodedSize values, it might be impossible to generate |
||||
// the string with the desired encodedSize using the algorithm above. For testing purposes, checking that |
||||
// the encoded size we got is actually correct is good enough. |
||||
if (CodedOutputStream.ComputeStringSize(str) != encodedSize) |
||||
{ |
||||
throw new InvalidOperationException($"Generated string with wrong encodedSize"); |
||||
} |
||||
return str; |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,198 +0,0 @@ |
||||
#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; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,516 +0,0 @@ |
||||
#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.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); |
||||
for (int i = 0; i < values.Length; i++) |
||||
{ |
||||
cos.WriteRawVarint32(values[i]); |
||||
} |
||||
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); |
||||
for (int i = 0; i < values.Length; i++) |
||||
{ |
||||
ctx.WriteUInt32(values[i]); |
||||
} |
||||
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); |
||||
for (int i = 0; i < values.Length; i++) |
||||
{ |
||||
cos.WriteRawVarint64(values[i]); |
||||
} |
||||
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); |
||||
for (int i = 0; i < values.Length; i++) |
||||
{ |
||||
ctx.WriteUInt64(values[i]); |
||||
} |
||||
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 WriteRawTag_OneByte_WriteContext() |
||||
{ |
||||
const int encodedSize = 1; |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
for (uint i = 0; i < BytesToWrite / encodedSize; i++) |
||||
{ |
||||
ctx.WriteRawTag(16); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void WriteRawTag_TwoBytes_WriteContext() |
||||
{ |
||||
const int encodedSize = 2; |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
for (uint i = 0; i < BytesToWrite / encodedSize; i++) |
||||
{ |
||||
ctx.WriteRawTag(137, 6); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void WriteRawTag_ThreeBytes_WriteContext() |
||||
{ |
||||
const int encodedSize = 3; |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
for (uint i = 0; i < BytesToWrite / encodedSize; i++) |
||||
{ |
||||
ctx.WriteRawTag(160, 131, 1); |
||||
} |
||||
ctx.Flush(); |
||||
ctx.CheckNoSpaceLeft(); |
||||
} |
||||
|
||||
[Benchmark] |
||||
public void Baseline_WriteContext() |
||||
{ |
||||
var span = new Span<byte>(outputBuffer); |
||||
WriteContext.Initialize(ref span, out WriteContext ctx); |
||||
ctx.state.position = outputBuffer.Length; |
||||
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; |
||||
} |
||||
} |
||||
} |
@ -1,237 +0,0 @@ |
||||
syntax = "proto3"; |
||||
|
||||
package google.protobuf.benchmarks; |
||||
|
||||
import "google/protobuf/wrappers.proto"; |
||||
|
||||
// a message that has a large number of wrapper fields |
||||
// obfuscated version of an internal message |
||||
message ManyWrapperFieldsMessage { |
||||
google.protobuf.DoubleValue double_field_95 = 95; |
||||
google.protobuf.DoubleValue double_field_1 = 1; |
||||
google.protobuf.DoubleValue double_field_79 = 79; |
||||
google.protobuf.Int64Value int64_field_2 = 2; |
||||
google.protobuf.DoubleValue double_field_96 = 96; |
||||
google.protobuf.Int64Value int64_field_3 = 3; |
||||
google.protobuf.Int64Value int64_field_4 = 4; |
||||
google.protobuf.DoubleValue double_field_97 = 97; |
||||
google.protobuf.DoubleValue double_field_65 = 65; |
||||
google.protobuf.DoubleValue double_field_66 = 66; |
||||
google.protobuf.DoubleValue double_field_7 = 7; |
||||
google.protobuf.DoubleValue double_field_62 = 62; |
||||
google.protobuf.DoubleValue double_field_118 = 118; |
||||
google.protobuf.DoubleValue double_field_119 = 119; |
||||
google.protobuf.DoubleValue double_field_67 = 67; |
||||
google.protobuf.DoubleValue double_field_120 = 120; |
||||
google.protobuf.DoubleValue double_field_121 = 121; |
||||
google.protobuf.DoubleValue double_field_122 = 122; |
||||
google.protobuf.DoubleValue double_field_123 = 123; |
||||
google.protobuf.DoubleValue double_field_124 = 124; |
||||
google.protobuf.DoubleValue double_field_8 = 8; |
||||
google.protobuf.DoubleValue double_field_9 = 9; |
||||
google.protobuf.DoubleValue double_field_98 = 98; |
||||
google.protobuf.DoubleValue double_field_10 = 10; |
||||
google.protobuf.DoubleValue double_field_11 = 11; |
||||
google.protobuf.DoubleValue double_field_99 = 99; |
||||
google.protobuf.DoubleValue double_field_84 = 84; |
||||
google.protobuf.DoubleValue double_field_14 = 14; |
||||
google.protobuf.DoubleValue double_field_77 = 77; |
||||
google.protobuf.DoubleValue double_field_15 = 15; |
||||
google.protobuf.Int64Value int64_field_19 = 19; |
||||
google.protobuf.Int64Value int64_field_115 = 115; |
||||
google.protobuf.DoubleValue double_field_116 = 116; |
||||
google.protobuf.Int64Value int64_field_117 = 117; |
||||
google.protobuf.DoubleValue double_field_20 = 20; |
||||
google.protobuf.DoubleValue double_field_21 = 21; |
||||
google.protobuf.StringValue string_field_73 = 73; |
||||
google.protobuf.StringValue string_field_74 = 74; |
||||
google.protobuf.DoubleValue double_field_22 = 22; |
||||
google.protobuf.DoubleValue double_field_69 = 69; |
||||
google.protobuf.DoubleValue double_field_70 = 70; |
||||
google.protobuf.DoubleValue double_field_71 = 71; |
||||
google.protobuf.DoubleValue double_field_72 = 72; |
||||
google.protobuf.DoubleValue double_field_25 = 25; |
||||
google.protobuf.Int64Value int64_field_26 = 26; |
||||
google.protobuf.DoubleValue double_field_68 = 68; |
||||
google.protobuf.DoubleValue double_field_28 = 28; |
||||
google.protobuf.DoubleValue double_field_106 = 106; |
||||
google.protobuf.DoubleValue double_field_29 = 29; |
||||
google.protobuf.DoubleValue double_field_30 = 30; |
||||
google.protobuf.DoubleValue double_field_101 = 101; |
||||
google.protobuf.DoubleValue double_field_102 = 102; |
||||
google.protobuf.DoubleValue double_field_103 = 103; |
||||
google.protobuf.DoubleValue double_field_104 = 104; |
||||
google.protobuf.DoubleValue double_field_105 = 105; |
||||
google.protobuf.DoubleValue double_field_31 = 31; |
||||
google.protobuf.Int64Value int64_field_32 = 32; |
||||
google.protobuf.DoubleValue double_field_75 = 75; |
||||
google.protobuf.DoubleValue double_field_129 = 129; |
||||
int32 enum_field_80 = 80; |
||||
int32 enum_field_81 = 81; |
||||
google.protobuf.Int64Value int64_field_82 = 82; |
||||
int32 enum_field_83 = 83; |
||||
google.protobuf.Int64Value int64_field_85 = 85; |
||||
google.protobuf.Int64Value int64_field_86 = 86; |
||||
google.protobuf.Int64Value int64_field_87 = 87; |
||||
google.protobuf.Int64Value int64_field_125 = 125; |
||||
google.protobuf.Int64Value int64_field_37 = 37; |
||||
google.protobuf.DoubleValue double_field_38 = 38; |
||||
google.protobuf.Int64Value interactions = 39; |
||||
repeated int32 repeated_int_field_100 = 100; |
||||
google.protobuf.DoubleValue double_field_40 = 40; |
||||
google.protobuf.Int64Value int64_field_41 = 41; |
||||
google.protobuf.Int64Value int64_field_126 = 126; |
||||
google.protobuf.Int64Value int64_field_127 = 127; |
||||
google.protobuf.DoubleValue double_field_128 = 128; |
||||
google.protobuf.DoubleValue double_field_109 = 109; |
||||
google.protobuf.Int64Value int64_field_110 = 110; |
||||
google.protobuf.DoubleValue double_field_111 = 111; |
||||
google.protobuf.Int64Value int64_field_112 = 112; |
||||
google.protobuf.DoubleValue double_field_113 = 113; |
||||
google.protobuf.Int64Value int64_field_114 = 114; |
||||
google.protobuf.DoubleValue double_field_42 = 42; |
||||
google.protobuf.Int64Value int64_field_43 = 43; |
||||
google.protobuf.Int64Value int64_field_44 = 44; |
||||
google.protobuf.DoubleValue double_field_45 = 45; |
||||
google.protobuf.DoubleValue double_field_46 = 46; |
||||
google.protobuf.DoubleValue double_field_78 = 78; |
||||
google.protobuf.DoubleValue double_field_88 = 88; |
||||
google.protobuf.DoubleValue double_field_47 = 47; |
||||
google.protobuf.DoubleValue double_field_89 = 89; |
||||
google.protobuf.DoubleValue double_field_48 = 48; |
||||
google.protobuf.DoubleValue double_field_49 = 49; |
||||
google.protobuf.DoubleValue double_field_50 = 50; |
||||
google.protobuf.DoubleValue double_field_90 = 90; |
||||
google.protobuf.DoubleValue double_field_51 = 51; |
||||
google.protobuf.DoubleValue double_field_91 = 91; |
||||
google.protobuf.DoubleValue double_field_92 = 92; |
||||
google.protobuf.Int64Value int64_field_107 = 107; |
||||
google.protobuf.DoubleValue double_field_93 = 93; |
||||
google.protobuf.DoubleValue double_field_108 = 108; |
||||
google.protobuf.DoubleValue double_field_52 = 52; |
||||
google.protobuf.DoubleValue double_field_53 = 53; |
||||
google.protobuf.DoubleValue double_field_94 = 94; |
||||
google.protobuf.DoubleValue double_field_54 = 54; |
||||
google.protobuf.DoubleValue double_field_55 = 55; |
||||
google.protobuf.DoubleValue double_field_56 = 56; |
||||
google.protobuf.DoubleValue double_field_57 = 57; |
||||
google.protobuf.DoubleValue double_field_58 = 58; |
||||
google.protobuf.Int64Value int64_field_59 = 59; |
||||
google.protobuf.Int64Value int64_field_60 = 60; |
||||
} |
||||
|
||||
// same as ManyWrapperFieldsMessages, but with primitive fields |
||||
// for comparison. |
||||
message ManyPrimitiveFieldsMessage { |
||||
double double_field_95 = 95; |
||||
double double_field_1 = 1; |
||||
double double_field_79 = 79; |
||||
int64 int64_field_2 = 2; |
||||
double double_field_96 = 96; |
||||
int64 int64_field_3 = 3; |
||||
int64 int64_field_4 = 4; |
||||
double double_field_97 = 97; |
||||
double double_field_65 = 65; |
||||
double double_field_66 = 66; |
||||
double double_field_7 = 7; |
||||
double double_field_62 = 62; |
||||
double double_field_118 = 118; |
||||
double double_field_119 = 119; |
||||
double double_field_67 = 67; |
||||
double double_field_120 = 120; |
||||
double double_field_121 = 121; |
||||
double double_field_122 = 122; |
||||
double double_field_123 = 123; |
||||
double double_field_124 = 124; |
||||
double double_field_8 = 8; |
||||
double double_field_9 = 9; |
||||
double double_field_98 = 98; |
||||
double double_field_10 = 10; |
||||
double double_field_11 = 11; |
||||
double double_field_99 = 99; |
||||
double double_field_84 = 84; |
||||
double double_field_14 = 14; |
||||
double double_field_77 = 77; |
||||
double double_field_15 = 15; |
||||
int64 int64_field_19 = 19; |
||||
int64 int64_field_115 = 115; |
||||
double double_field_116 = 116; |
||||
int64 int64_field_117 = 117; |
||||
double double_field_20 = 20; |
||||
double double_field_21 = 21; |
||||
string string_field_73 = 73; |
||||
string string_field_74 = 74; |
||||
double double_field_22 = 22; |
||||
double double_field_69 = 69; |
||||
double double_field_70 = 70; |
||||
double double_field_71 = 71; |
||||
double double_field_72 = 72; |
||||
double double_field_25 = 25; |
||||
int64 int64_field_26 = 26; |
||||
double double_field_68 = 68; |
||||
double double_field_28 = 28; |
||||
double double_field_106 = 106; |
||||
double double_field_29 = 29; |
||||
double double_field_30 = 30; |
||||
double double_field_101 = 101; |
||||
double double_field_102 = 102; |
||||
double double_field_103 = 103; |
||||
double double_field_104 = 104; |
||||
double double_field_105 = 105; |
||||
double double_field_31 = 31; |
||||
int64 int64_field_32 = 32; |
||||
double double_field_75 = 75; |
||||
double double_field_129 = 129; |
||||
int32 enum_field_80 = 80; |
||||
int32 enum_field_81 = 81; |
||||
int64 int64_field_82 = 82; |
||||
int32 enum_field_83 = 83; |
||||
int64 int64_field_85 = 85; |
||||
int64 int64_field_86 = 86; |
||||
int64 int64_field_87 = 87; |
||||
int64 int64_field_125 = 125; |
||||
int64 int64_field_37 = 37; |
||||
double double_field_38 = 38; |
||||
int64 interactions = 39; |
||||
repeated int32 repeated_int_field_100 = 100; |
||||
double double_field_40 = 40; |
||||
int64 int64_field_41 = 41; |
||||
int64 int64_field_126 = 126; |
||||
int64 int64_field_127 = 127; |
||||
double double_field_128 = 128; |
||||
double double_field_109 = 109; |
||||
int64 int64_field_110 = 110; |
||||
double double_field_111 = 111; |
||||
int64 int64_field_112 = 112; |
||||
double double_field_113 = 113; |
||||
int64 int64_field_114 = 114; |
||||
double double_field_42 = 42; |
||||
int64 int64_field_43 = 43; |
||||
int64 int64_field_44 = 44; |
||||
double double_field_45 = 45; |
||||
double double_field_46 = 46; |
||||
double double_field_78 = 78; |
||||
double double_field_88 = 88; |
||||
double double_field_47 = 47; |
||||
double double_field_89 = 89; |
||||
double double_field_48 = 48; |
||||
double double_field_49 = 49; |
||||
double double_field_50 = 50; |
||||
double double_field_90 = 90; |
||||
double double_field_51 = 51; |
||||
double double_field_91 = 91; |
||||
double double_field_92 = 92; |
||||
int64 int64_field_107 = 107; |
||||
double double_field_93 = 93; |
||||
double double_field_108 = 108; |
||||
double double_field_52 = 52; |
||||
double double_field_53 = 53; |
||||
double double_field_94 = 94; |
||||
double double_field_54 = 54; |
||||
double double_field_55 = 55; |
||||
double double_field_56 = 56; |
||||
double double_field_57 = 57; |
||||
double double_field_58 = 58; |
||||
int64 int64_field_59 = 59; |
||||
int64 int64_field_60 = 60; |
||||
} |
Binary file not shown.
@ -1,304 +0,0 @@ |
||||
# Protobuf Performance |
||||
The following benchmark test results were produced on a workstation utilizing an Intel® Xeon® Processor E5-2630 with 32GB of RAM. |
||||
|
||||
This table contains the results of three separate languages: |
||||
|
||||
* **C++** - For C++, there are three parsing methods: |
||||
* **new** - This is for using a new operator for creating a message instance. |
||||
* **new arena** - This is for using arena for creating a new message instance. |
||||
* **reuse** - This is for reusing the same message instance for parsing. |
||||
* **Java** - For Java, there are three parsing/serialization methods: |
||||
* **byte[]** - This is for parsing from a Byte Array. |
||||
* **ByteString** - This is for parsing from a |
||||
com.google.protobuf.ByteString. |
||||
* **InputStream** - This is for parsing from an InputStream. |
||||
* **Python** - For Python, there are three types of Python protobuf for testing: |
||||
* **C++-generated-code** - This is for using C++ generated code of the |
||||
proto file as a dynamic linked library. |
||||
* **C++-reflection** - This is for using C++ reflection, for which there's no |
||||
generated code, but still using C++ protobuf library as a dynamic linked |
||||
library. |
||||
* **pure-Python** - This is for the pure version of Python, which does not link with |
||||
any C++ protobuf library. |
||||
|
||||
## Parsing performance |
||||
|
||||
<table> |
||||
<tbody><tr> |
||||
<th rowspan="2"> </th> |
||||
<th colspan="3" rowspan="1">C++</th> |
||||
<th colspan="3" rowspan="1">C++ with tcmalloc</th> |
||||
<th colspan="3" rowspan="1">java</th> |
||||
<th colspan="3" rowspan="1">python</th> |
||||
</tr> |
||||
<tr> |
||||
<th colspan="1">new</th> |
||||
<th colspan="1">new arena</th> |
||||
<th colspan="1">reuse</th> |
||||
<th colspan="1">new</th> |
||||
<th colspan="1">new arena</th> |
||||
<th colspan="1">reuse</th> |
||||
<th colspan="1">byte[]</th> |
||||
<th colspan="1">ByteString</th> |
||||
<th colspan="1">InputStream</th> |
||||
<th colspan="1">C++-generated-code</th> |
||||
<th colspan="1">C++-reflection</th> |
||||
<th colspan="1">pure-Python</th> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message1_proto2</td> |
||||
<td>368.717MB/s</td> |
||||
<td>261.847MB/s</td> |
||||
<td>799.403MB/s</td> |
||||
<td>645.183MB/s</td> |
||||
<td>441.023MB/s</td> |
||||
<td>1.122GB/s</td> |
||||
<td>425.437MB/s</td> |
||||
<td>425.937MB/s</td> |
||||
<td>251.018MB/s</td> |
||||
<td>82.8314MB/s</td> |
||||
<td>47.6763MB/s</td> |
||||
<td>3.76299MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message1_proto3</td> |
||||
<td>294.517MB/s</td> |
||||
<td>229.116MB/s</td> |
||||
<td>469.982MB/s</td> |
||||
<td>434.510MB/s</td> |
||||
<td>394.701MB/s</td> |
||||
<td>591.931MB/s</td> |
||||
<td>357.597MB/s</td> |
||||
<td>378.568MB/s</td> |
||||
<td>221.676MB/s</td> |
||||
<td>82.0498MB/s</td> |
||||
<td>39.9467MB/s</td> |
||||
<td>3.77751MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message2</td> |
||||
<td>277.242MB/s</td> |
||||
<td>347.611MB/s</td> |
||||
<td>793.67MB/s</td> |
||||
<td>503.721MB/s</td> |
||||
<td>596.333MB/s</td> |
||||
<td>922.533MB/s</td> |
||||
<td>416.778MB/s</td> |
||||
<td>419.543MB/s</td> |
||||
<td>367.145MB/s</td> |
||||
<td>241.46MB/s</td> |
||||
<td>71.5723MB/s</td> |
||||
<td>2.73538MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message3_1</td> |
||||
<td>213.478MB/s</td> |
||||
<td>291.58MB/s</td> |
||||
<td>543.398MB/s</td> |
||||
<td>539.704MB/s</td> |
||||
<td>717.300MB/s</td> |
||||
<td>927.333MB/s</td> |
||||
<td>684.241MB/s</td> |
||||
<td>704.47MB/s</td> |
||||
<td>648.624MB/s</td> |
||||
<td>209.036MB/s</td> |
||||
<td>142.356MB/s</td> |
||||
<td>15.3324MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message3_2</td> |
||||
<td>672.685MB/s</td> |
||||
<td>802.767MB/s</td> |
||||
<td>1.21505GB/s</td> |
||||
<td>985.790MB/s</td> |
||||
<td>1.136GB/s</td> |
||||
<td>1.367GB/s</td> |
||||
<td>1.54439GB/s</td> |
||||
<td>1.60603GB/s</td> |
||||
<td>1.33443GB/s</td> |
||||
<td>573.835MB/s</td> |
||||
<td>314.33MB/s</td> |
||||
<td>15.0169MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message3_3</td> |
||||
<td>207.681MB/s</td> |
||||
<td>140.591MB/s</td> |
||||
<td>535.181MB/s</td> |
||||
<td>369.743MB/s</td> |
||||
<td>262.301MB/s</td> |
||||
<td>556.644MB/s</td> |
||||
<td>279.385MB/s</td> |
||||
<td>304.853MB/s</td> |
||||
<td>107.575MB/s</td> |
||||
<td>32.248MB/s</td> |
||||
<td>26.1431MB/s</td> |
||||
<td>2.63541MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message3_4</td> |
||||
<td>7.96091GB/s</td> |
||||
<td>7.10024GB/s</td> |
||||
<td>9.3013GB/s</td> |
||||
<td>8.518GB/s</td> |
||||
<td>8.171GB/s</td> |
||||
<td>9.917GB/s</td> |
||||
<td>5.78006GB/s</td> |
||||
<td>5.85198GB/s</td> |
||||
<td>4.62609GB/s</td> |
||||
<td>2.49631GB/s</td> |
||||
<td>2.35442GB/s</td> |
||||
<td>802.061MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message3_5</td> |
||||
<td>76.0072MB/s</td> |
||||
<td>51.6769MB/s</td> |
||||
<td>237.856MB/s</td> |
||||
<td>178.495MB/s</td> |
||||
<td>111.751MB/s</td> |
||||
<td>329.569MB/s</td> |
||||
<td>121.038MB/s</td> |
||||
<td>132.866MB/s</td> |
||||
<td>36.9197MB/s</td> |
||||
<td>10.3962MB/s</td> |
||||
<td>8.84659MB/s</td> |
||||
<td>1.25203MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message4</td> |
||||
<td>331.46MB/s</td> |
||||
<td>404.862MB/s</td> |
||||
<td>427.99MB/s</td> |
||||
<td>589.887MB/s</td> |
||||
<td>720.367MB/s</td> |
||||
<td>705.373MB/s</td> |
||||
<td>606.228MB/s</td> |
||||
<td>589.13MB/s</td> |
||||
<td>530.692MB/s</td> |
||||
<td>305.543MB/s</td> |
||||
<td>174.834MB/s</td> |
||||
<td>7.86485MB/s</td> |
||||
</tr> |
||||
</tbody></table> |
||||
|
||||
## Serialization performance |
||||
|
||||
<table> |
||||
<tbody><tr> |
||||
<th rowspan="2"> </th> |
||||
<th colspan="1" rowspan="2">C++</th> |
||||
<th colspan="1" rowspan="2">C++ with tcmalloc</th> |
||||
<th colspan="3" rowspan="1">java</th> |
||||
<th colspan="3" rowspan="1">python</th> |
||||
</tr> |
||||
<tr> |
||||
<th colspan="1">byte[]</th> |
||||
<th colspan="1">ByteString</th> |
||||
<th colspan="1">InputStream</th> |
||||
<th colspan="1">C++-generated-code</th> |
||||
<th colspan="1">C++-reflection</th> |
||||
<th colspan="1">pure-Python</th> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message1_proto2</td> |
||||
<td>1.39698GB/s</td> |
||||
<td>1.701GB/s</td> |
||||
<td>1.12915GB/s</td> |
||||
<td>1.13589GB/s</td> |
||||
<td>758.609MB/s</td> |
||||
<td>260.911MB/s</td> |
||||
<td>58.4815MB/s</td> |
||||
<td>5.77824MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message1_proto3</td> |
||||
<td>959.305MB/s</td> |
||||
<td>939.404MB/s</td> |
||||
<td>1.15372GB/s</td> |
||||
<td>1.07824GB/s</td> |
||||
<td>802.337MB/s</td> |
||||
<td>239.4MB/s</td> |
||||
<td>33.6336MB/s</td> |
||||
<td>5.80524MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message2</td> |
||||
<td>1.27429GB/s</td> |
||||
<td>1.402GB/s</td> |
||||
<td>1.01039GB/s</td> |
||||
<td>1022.99MB/s</td> |
||||
<td>798.736MB/s</td> |
||||
<td>996.755MB/s</td> |
||||
<td>57.9601MB/s</td> |
||||
<td>4.09246MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message3_1</td> |
||||
<td>1.31916GB/s</td> |
||||
<td>2.049GB/s</td> |
||||
<td>991.496MB/s</td> |
||||
<td>860.332MB/s</td> |
||||
<td>662.88MB/s</td> |
||||
<td>1.48625GB/s</td> |
||||
<td>421.287MB/s</td> |
||||
<td>18.002MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message3_2</td> |
||||
<td>2.15676GB/s</td> |
||||
<td>2.632GB/s</td> |
||||
<td>2.14736GB/s</td> |
||||
<td>2.08136GB/s</td> |
||||
<td>1.55997GB/s</td> |
||||
<td>2.39597GB/s</td> |
||||
<td>326.777MB/s</td> |
||||
<td>16.0527MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message3_3</td> |
||||
<td>650.456MB/s</td> |
||||
<td>1.040GB/s</td> |
||||
<td>593.52MB/s</td> |
||||
<td>580.667MB/s</td> |
||||
<td>346.839MB/s</td> |
||||
<td>123.978MB/s</td> |
||||
<td>35.893MB/s</td> |
||||
<td>2.32834MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message3_4</td> |
||||
<td>8.70154GB/s</td> |
||||
<td>9.825GB/s</td> |
||||
<td>5.88645GB/s</td> |
||||
<td>5.93946GB/s</td> |
||||
<td>2.44388GB/s</td> |
||||
<td>5.9241GB/s</td> |
||||
<td>4.05837GB/s</td> |
||||
<td>876.87MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message3_5</td> |
||||
<td>246.33MB/s</td> |
||||
<td>443.993MB/s</td> |
||||
<td>283.278MB/s</td> |
||||
<td>259.167MB/s</td> |
||||
<td>206.37MB/s</td> |
||||
<td>37.0285MB/s</td> |
||||
<td>12.2228MB/s</td> |
||||
<td>1.1979MB/s</td> |
||||
</tr> |
||||
<tr> |
||||
<td>google_message4</td> |
||||
<td>1.56674GB/s</td> |
||||
<td>2.19601GB/s</td> |
||||
<td>776.907MB/s</td> |
||||
<td>770.707MB/s</td> |
||||
<td>702.931MB/s</td> |
||||
<td>1.49623GB/s</td> |
||||
<td>205.116MB/s</td> |
||||
<td>8.93428MB/s</td> |
||||
</tr> |
||||
</tbody></table> |
||||
|
||||
\* The cpp performance can be improved by using [tcmalloc](https://gperftools.github.io/gperftools/tcmalloc.html), please follow the (instruction)[https://github.com/protocolbuffers/protobuf/blob/main/benchmarks/README.md] to link with tcmalloc to get the faster result. |
@ -1,11 +0,0 @@ |
||||
# Config file for running tests in Kokoro |
||||
|
||||
# Location of the build script in repository |
||||
build_file: "protobuf/kokoro/linux/benchmark/run.sh" |
||||
timeout_mins: 240 |
||||
|
||||
action { |
||||
define_artifacts { |
||||
regex: "**/sponge_log.xml" |
||||
} |
||||
} |
@ -1,66 +0,0 @@ |
||||
#!/bin/bash |
||||
# |
||||
# Install Bazel 4.2.2. |
||||
use_bazel.sh 4.2.2 |
||||
|
||||
# Change to repo root |
||||
cd $(dirname $0)/../../.. |
||||
SCRIPT_ROOT=$(pwd) |
||||
|
||||
set -ex |
||||
|
||||
export OUTPUT_DIR=testoutput |
||||
repo_root="$(pwd)" |
||||
|
||||
# Setup python environment. |
||||
pyenv install -v 3.9.5 -s |
||||
pyenv global 3.9.5 |
||||
pyenv versions |
||||
python --version |
||||
python -m venv "venv" |
||||
source "venv/bin/activate" |
||||
|
||||
# TODO(jtattermusch): Add back support for benchmarking with tcmalloc for C++ and python. |
||||
# This feature was removed since it used to use tcmalloc from https://github.com/gperftools/gperftools.git |
||||
# which is very outdated. See https://github.com/protocolbuffers/protobuf/issues/8725. |
||||
|
||||
# download datasets for benchmark |
||||
pushd benchmarks |
||||
datasets=$(for file in $(find . -type f -name "dataset.*.pb" -not -path "./tmp/*"); do echo "$(pwd)/$file"; done | xargs) |
||||
echo $datasets |
||||
popd |
||||
|
||||
# build and run Python benchmark |
||||
echo "benchmarking pure python..." |
||||
${SCRIPT_ROOT}/kokoro/common/bazel_wrapper.sh run //benchmarks/python:python_benchmark -- \ |
||||
--json --behavior_prefix="pure-python-benchmark" $datasets > /tmp/python1.json |
||||
echo "benchmarking python cpp reflection..." |
||||
${SCRIPT_ROOT}/kokoro/common/bazel_wrapper.sh run //benchmarks/python:python_benchmark --define=use_fast_cpp_protos=true -- \ |
||||
--json --behavior_prefix="cpp-reflection-benchmark" $datasets > /tmp/python2.json |
||||
echo "benchmarking python cpp generated code..." |
||||
${SCRIPT_ROOT}/kokoro/common/bazel_wrapper.sh run //benchmarks/python:python_benchmark --define=use_fast_cpp_protos=true -- \ |
||||
--json --cpp_generated --behavior_prefix="cpp-generated-code-benchmark" $datasets >> /tmp/python3.json |
||||
|
||||
jq -s . /tmp/python1.json /tmp/python2.json /tmp/python3.json > python_result.json |
||||
|
||||
# build and run C++ benchmark |
||||
echo "benchmarking cpp..." |
||||
${SCRIPT_ROOT}/kokoro/common/bazel_wrapper.sh run //benchmarks/cpp:cpp_benchmark -- \ |
||||
--benchmark_min_time=5.0 --benchmark_out_format=json --benchmark_out="${repo_root}/cpp_result.json" $datasets |
||||
|
||||
# build and run java benchmark (java 11 is required) |
||||
echo "benchmarking java..." |
||||
${SCRIPT_ROOT}/kokoro/common/bazel_wrapper.sh run //benchmarks/java:java_benchmark -- \ |
||||
-Cresults.file.options.file="${repo_root}/java_result.json" $datasets |
||||
|
||||
# persist raw the results in the build job log (for better debuggability) |
||||
cat cpp_result.json |
||||
cat java_result.json |
||||
cat python_result.json |
||||
|
||||
# print the postprocessed results to the build job log |
||||
# TODO(jtattermusch): re-enable uploading results to bigquery (it is currently broken) |
||||
bazel run //benchmarks/util:result_parser -- \ |
||||
-cpp="${repo_root}/cpp_result.json" \ |
||||
-java="${repo_root}/java_result.json" \ |
||||
-python="${repo_root}/python_result.json" |
@ -0,0 +1,12 @@ |
||||
objc.protobuf.tests = "" # Explicit empty prefix |
||||
objc.protobuf.tests.any = Any |
||||
objc.protobuf.tests.chain = Chain |
||||
objc.protobuf.tests.cycle = Cycle |
||||
objc.protobuf.tests.deprecated = Dep |
||||
objc.protobuf.tests.deprecated_file = FileDep |
||||
objc.protobuf.tests.import = Import |
||||
objc.protobuf.tests.mset = MSet |
||||
objc.protobuf.tests.options = GPBTEST |
||||
objc.protobuf.tests.proto3_preserve_unknown_enum = UnknownEnums |
||||
objc.protobuf.tests.public_import = PublicImport |
||||
objc.protobuf.tests.startup = TestObjCStartup |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue