Merge pull request #7658 from jtattermusch/csharp_benchmark_improvements

C# write benchmark improvements
pull/7673/head
Jan Tattermusch 5 years ago committed by GitHub
commit 62cf7c6096
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj
  2. 68
      csharp/src/Google.Protobuf.Benchmarks/WriteRawPrimitivesBenchmark.cs
  3. 14
      csharp/src/Google.Protobuf/WritingPrimitives.cs

@ -2,15 +2,17 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly> <SignAssembly>true</SignAssembly>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign> <PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<IsPackable>False</IsPackable> <IsPackable>False</IsPackable>
<DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.4" /> <PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
<ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj" /> <ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj" />
</ItemGroup> </ItemGroup>

@ -123,9 +123,9 @@ namespace Google.Protobuf.Benchmarks
{ {
var values = varint32Values[encodedSize]; var values = varint32Values[encodedSize];
var cos = new CodedOutputStream(outputBuffer); var cos = new CodedOutputStream(outputBuffer);
foreach (var value in values) for (int i = 0; i < values.Length; i++)
{ {
cos.WriteRawVarint32(value); cos.WriteRawVarint32(values[i]);
} }
cos.Flush(); cos.Flush();
cos.CheckNoSpaceLeft(); cos.CheckNoSpaceLeft();
@ -142,9 +142,9 @@ namespace Google.Protobuf.Benchmarks
var values = varint32Values[encodedSize]; var values = varint32Values[encodedSize];
var span = new Span<byte>(outputBuffer); var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx); WriteContext.Initialize(ref span, out WriteContext ctx);
foreach (var value in values) for (int i = 0; i < values.Length; i++)
{ {
ctx.WriteUInt32(value); ctx.WriteUInt32(values[i]);
} }
ctx.Flush(); ctx.Flush();
ctx.CheckNoSpaceLeft(); ctx.CheckNoSpaceLeft();
@ -165,9 +165,9 @@ namespace Google.Protobuf.Benchmarks
{ {
var values = varint64Values[encodedSize]; var values = varint64Values[encodedSize];
var cos = new CodedOutputStream(outputBuffer); var cos = new CodedOutputStream(outputBuffer);
foreach (var value in values) for (int i = 0; i < values.Length; i++)
{ {
cos.WriteRawVarint64(value); cos.WriteRawVarint64(values[i]);
} }
cos.Flush(); cos.Flush();
cos.CheckNoSpaceLeft(); cos.CheckNoSpaceLeft();
@ -189,9 +189,9 @@ namespace Google.Protobuf.Benchmarks
var values = varint64Values[encodedSize]; var values = varint64Values[encodedSize];
var span = new Span<byte>(outputBuffer); var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx); WriteContext.Initialize(ref span, out WriteContext ctx);
foreach (var value in values) for (int i = 0; i < values.Length; i++)
{ {
ctx.WriteUInt64(value); ctx.WriteUInt64(values[i]);
} }
ctx.Flush(); ctx.Flush();
ctx.CheckNoSpaceLeft(); ctx.CheckNoSpaceLeft();
@ -251,6 +251,58 @@ namespace Google.Protobuf.Benchmarks
ctx.CheckNoSpaceLeft(); 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] [Benchmark]
public void WriteRawFloat_CodedOutputStream() public void WriteRawFloat_CodedOutputStream()
{ {

@ -384,18 +384,8 @@ namespace Google.Protobuf
} }
else else
{ {
// TODO(jtattermusch): According to the benchmarks, writing byte-by-byte is actually faster BinaryPrimitives.WriteUInt64LittleEndian(buffer.Slice(state.position), value);
// than using BinaryPrimitives.WriteUInt64LittleEndian. state.position += length;
// This is strange especially because WriteUInt32LittleEndian seems to be much faster
// in terms of throughput.
buffer[state.position++] = ((byte)value);
buffer[state.position++] = ((byte)(value >> 8));
buffer[state.position++] = ((byte)(value >> 16));
buffer[state.position++] = ((byte)(value >> 24));
buffer[state.position++] = ((byte)(value >> 32));
buffer[state.position++] = ((byte)(value >> 40));
buffer[state.position++] = ((byte)(value >> 48));
buffer[state.position++] = ((byte)(value >> 56));
} }
} }

Loading…
Cancel
Save