From 549dc9a41267a410e9783760fd899bdd1779698e Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 9 Jun 2020 17:59:32 +0200 Subject: [PATCH] optimize writing fixed32 and fixed64, fix benchmark --- .../WriteRawPrimitivesBenchmark.cs | 2 +- csharp/src/Google.Protobuf/WritingPrimitives.cs | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/csharp/src/Google.Protobuf.Benchmarks/WriteRawPrimitivesBenchmark.cs b/csharp/src/Google.Protobuf.Benchmarks/WriteRawPrimitivesBenchmark.cs index 4df43ed7e..891b877b6 100644 --- a/csharp/src/Google.Protobuf.Benchmarks/WriteRawPrimitivesBenchmark.cs +++ b/csharp/src/Google.Protobuf.Benchmarks/WriteRawPrimitivesBenchmark.cs @@ -240,7 +240,7 @@ namespace Google.Protobuf.Benchmarks [Benchmark] public void WriteFixed64_WriteContext() { - const int encodedSize = sizeof(uint); + const int encodedSize = sizeof(ulong); var span = new Span(outputBuffer); WriteContext.Initialize(ref span, out WriteContext ctx); for (uint i = 0; i < BytesToWrite / encodedSize; i++) diff --git a/csharp/src/Google.Protobuf/WritingPrimitives.cs b/csharp/src/Google.Protobuf/WritingPrimitives.cs index 9b2ee4b53..4c77b59b9 100644 --- a/csharp/src/Google.Protobuf/WritingPrimitives.cs +++ b/csharp/src/Google.Protobuf/WritingPrimitives.cs @@ -31,6 +31,7 @@ #endregion using System; +using System.Buffers.Binary; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; @@ -351,7 +352,8 @@ namespace Google.Protobuf [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteRawLittleEndian32(ref Span buffer, ref WriterInternalState state, uint value) { - if (state.position + 4 > state.limit) + const int length = sizeof(uint); + if (state.position + length > state.limit) { WriteRawByte(ref buffer, ref state, (byte)value); WriteRawByte(ref buffer, ref state, (byte)(value >> 8)); @@ -360,17 +362,16 @@ namespace Google.Protobuf } else { - buffer[state.position++] = ((byte)value); - buffer[state.position++] = ((byte)(value >> 8)); - buffer[state.position++] = ((byte)(value >> 16)); - buffer[state.position++] = ((byte)(value >> 24)); + BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(state.position), value); + state.position += length; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteRawLittleEndian64(ref Span buffer, ref WriterInternalState state, ulong value) { - if (state.position + 8 > state.limit) + const int length = sizeof(ulong); + if (state.position + length > state.limit) { WriteRawByte(ref buffer, ref state, (byte)value); WriteRawByte(ref buffer, ref state, (byte)(value >> 8)); @@ -383,6 +384,10 @@ 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));