Explorar o código

Merge pull request #7658 from jtattermusch/csharp_benchmark_improvements

C# write benchmark improvements
Jan Tattermusch %!s(int64=5) %!d(string=hai) anos
pai
achega
62cf7c6096

+ 4 - 2
csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj

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

+ 61 - 9
csharp/src/Google.Protobuf.Benchmarks/WriteRawPrimitivesBenchmark.cs

@@ -123,9 +123,9 @@ namespace Google.Protobuf.Benchmarks
         {
             var values = varint32Values[encodedSize];
             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.CheckNoSpaceLeft();
@@ -142,9 +142,9 @@ namespace Google.Protobuf.Benchmarks
             var values = varint32Values[encodedSize];
             var span = new Span<byte>(outputBuffer);
             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.CheckNoSpaceLeft();
@@ -165,9 +165,9 @@ namespace Google.Protobuf.Benchmarks
         {
             var values = varint64Values[encodedSize];
             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.CheckNoSpaceLeft();
@@ -189,9 +189,9 @@ namespace Google.Protobuf.Benchmarks
             var values = varint64Values[encodedSize];
             var span = new Span<byte>(outputBuffer);
             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.CheckNoSpaceLeft();
@@ -202,7 +202,7 @@ namespace Google.Protobuf.Benchmarks
         {
             const int encodedSize = sizeof(uint);
             var cos = new CodedOutputStream(outputBuffer);
-            for(int i = 0; i < BytesToWrite / encodedSize; i++)
+            for (int i = 0; i < BytesToWrite / encodedSize; i++)
             {
                 cos.WriteFixed32(12345);
             }
@@ -251,6 +251,58 @@ namespace Google.Protobuf.Benchmarks
             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()
         {

+ 2 - 12
csharp/src/Google.Protobuf/WritingPrimitives.cs

@@ -384,18 +384,8 @@ namespace Google.Protobuf
             }
             else
             {
-                // TODO(jtattermusch): According to the benchmarks, writing byte-by-byte is actually faster
-                // than using BinaryPrimitives.WriteUInt64LittleEndian.
-                // 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));
+                BinaryPrimitives.WriteUInt64LittleEndian(buffer.Slice(state.position), value);
+                state.position += length;
             }
         }