From 28a6740179fe03d06ea2e641146ba42d60e50a6f Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:09:57 +0000 Subject: [PATCH 1/3] BinaryWriter perf improvements --- .../src/System/IO/BinaryWriter.cs | 81 +++++++++---------- 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs index b6fef2e0dadeef..54b78df024e2a1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs @@ -243,9 +243,14 @@ public virtual void Write(char[] chars, int index, int count) // public virtual void Write(double value) { - Span buffer = stackalloc byte[sizeof(double)]; - BinaryPrimitives.WriteDoubleLittleEndian(buffer, value); - OutStream.Write(buffer); + if (BitConverter.IsLittleEndian) + { + WriteBytes(value); + } + else + { + WriteBytes(BinaryPrimitives.ReverseEndianness(BitConverter.DoubleToUInt64Bits(value))); + } } public virtual void Write(decimal value) @@ -258,74 +263,49 @@ public virtual void Write(decimal value) // Writes a two-byte signed integer to this stream. The current position of // the stream is advanced by two. // - public virtual void Write(short value) - { - Span buffer = stackalloc byte[sizeof(short)]; - BinaryPrimitives.WriteInt16LittleEndian(buffer, value); - OutStream.Write(buffer); - } + public virtual void Write(short value) => WriteBytes(BitConverter.IsLittleEndian ? (ushort)value : BinaryPrimitives.ReverseEndianness((ushort)value)); // Writes a two-byte unsigned integer to this stream. The current position // of the stream is advanced by two. // [CLSCompliant(false)] - public virtual void Write(ushort value) - { - Span buffer = stackalloc byte[sizeof(ushort)]; - BinaryPrimitives.WriteUInt16LittleEndian(buffer, value); - OutStream.Write(buffer); - } + public virtual void Write(ushort value) => WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value)); // Writes a four-byte signed integer to this stream. The current position // of the stream is advanced by four. // - public virtual void Write(int value) - { - Span buffer = stackalloc byte[sizeof(int)]; - BinaryPrimitives.WriteInt32LittleEndian(buffer, value); - OutStream.Write(buffer); - } + public virtual void Write(int value) => WriteBytes(BitConverter.IsLittleEndian ? (uint)value : BinaryPrimitives.ReverseEndianness((uint)value)); // Writes a four-byte unsigned integer to this stream. The current position // of the stream is advanced by four. // [CLSCompliant(false)] - public virtual void Write(uint value) - { - Span buffer = stackalloc byte[sizeof(uint)]; - BinaryPrimitives.WriteUInt32LittleEndian(buffer, value); - OutStream.Write(buffer); - } + public virtual void Write(uint value) => WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value)); // Writes an eight-byte signed integer to this stream. The current position // of the stream is advanced by eight. // - public virtual void Write(long value) - { - Span buffer = stackalloc byte[sizeof(long)]; - BinaryPrimitives.WriteInt64LittleEndian(buffer, value); - OutStream.Write(buffer); - } + public virtual void Write(long value) => WriteBytes(BitConverter.IsLittleEndian ? (ulong)value : BinaryPrimitives.ReverseEndianness((ulong)value)); // Writes an eight-byte unsigned integer to this stream. The current // position of the stream is advanced by eight. // [CLSCompliant(false)] - public virtual void Write(ulong value) - { - Span buffer = stackalloc byte[sizeof(ulong)]; - BinaryPrimitives.WriteUInt64LittleEndian(buffer, value); - OutStream.Write(buffer); - } + public virtual void Write(ulong value) => WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value)); // Writes a float to this stream. The current position of the stream is // advanced by four. // public virtual void Write(float value) { - Span buffer = stackalloc byte[sizeof(float)]; - BinaryPrimitives.WriteSingleLittleEndian(buffer, value); - OutStream.Write(buffer); + if (BitConverter.IsLittleEndian) + { + WriteBytes(value); + } + else + { + WriteBytes(BinaryPrimitives.ReverseEndianness(BitConverter.SingleToUInt32Bits(value))); + } } // Writes a half to this stream. The current position of the stream is @@ -333,9 +313,20 @@ public virtual void Write(float value) // public virtual void Write(Half value) { - Span buffer = stackalloc byte[sizeof(ushort) /* = sizeof(Half) */]; - BinaryPrimitives.WriteHalfLittleEndian(buffer, value); - OutStream.Write(buffer); + if (BitConverter.IsLittleEndian) + { + WriteBytes(value); + } + else + { + WriteBytes(BinaryPrimitives.ReverseEndianness(BitConverter.HalfToUInt16Bits(value))); + } + } + + private void WriteBytes(T value) + where T : unmanaged + { + OutStream.Write(MemoryMarshal.AsBytes(new ReadOnlySpan(in value))); } // Writes a length-prefixed string to this stream in the BinaryWriter's From 46ea39ba82b619bc395b0706ec8c38f06e3d8bac Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:41:46 +0000 Subject: [PATCH 2/3] style: layout methods with braces --- .../src/System/IO/BinaryWriter.cs | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs index 54b78df024e2a1..b69c0726c9b040 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs @@ -135,18 +135,27 @@ public virtual long Seek(int offset, SeekOrigin origin) // Writes a boolean to this stream. A single byte is written to the stream // with the value 0 representing false or the value 1 representing true. // - public virtual void Write(bool value) => OutStream.WriteByte((byte)(value ? 1 : 0)); + public virtual void Write(bool value) + { + OutStream.WriteByte((byte)(value ? 1 : 0)); + } // Writes a byte to this stream. The current position of the stream is // advanced by one. // - public virtual void Write(byte value) => OutStream.WriteByte(value); + public virtual void Write(byte value) + { + OutStream.WriteByte(value); + } // Writes a signed byte to this stream. The current position of the stream // is advanced by one. // [CLSCompliant(false)] - public virtual void Write(sbyte value) => OutStream.WriteByte((byte)value); + public virtual void Write(sbyte value) + { + OutStream.WriteByte((byte)value); + } // Writes a byte array to this stream. // @@ -263,35 +272,53 @@ public virtual void Write(decimal value) // Writes a two-byte signed integer to this stream. The current position of // the stream is advanced by two. // - public virtual void Write(short value) => WriteBytes(BitConverter.IsLittleEndian ? (ushort)value : BinaryPrimitives.ReverseEndianness((ushort)value)); + public virtual void Write(short value) + { + WriteBytes(BitConverter.IsLittleEndian ? (ushort)value : BinaryPrimitives.ReverseEndianness((ushort)value)); + } // Writes a two-byte unsigned integer to this stream. The current position // of the stream is advanced by two. // [CLSCompliant(false)] - public virtual void Write(ushort value) => WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value)); + public virtual void Write(ushort value) + { + WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value)); + } // Writes a four-byte signed integer to this stream. The current position // of the stream is advanced by four. // - public virtual void Write(int value) => WriteBytes(BitConverter.IsLittleEndian ? (uint)value : BinaryPrimitives.ReverseEndianness((uint)value)); + public virtual void Write(int value) + { + WriteBytes(BitConverter.IsLittleEndian ? (uint)value : BinaryPrimitives.ReverseEndianness((uint)value)); + } // Writes a four-byte unsigned integer to this stream. The current position // of the stream is advanced by four. // [CLSCompliant(false)] - public virtual void Write(uint value) => WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value)); + public virtual void Write(uint value) + { + WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value)); + } // Writes an eight-byte signed integer to this stream. The current position // of the stream is advanced by eight. // - public virtual void Write(long value) => WriteBytes(BitConverter.IsLittleEndian ? (ulong)value : BinaryPrimitives.ReverseEndianness((ulong)value)); + public virtual void Write(long value) + { + WriteBytes(BitConverter.IsLittleEndian ? (ulong)value : BinaryPrimitives.ReverseEndianness((ulong)value)); + } // Writes an eight-byte unsigned integer to this stream. The current // position of the stream is advanced by eight. // [CLSCompliant(false)] - public virtual void Write(ulong value) => WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value)); + public virtual void Write(ulong value) + { + WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value)); + } // Writes a float to this stream. The current position of the stream is // advanced by four. From 19d98ec140dc34ab4cc30b9466b73faae83f3237 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 27 Mar 2024 23:02:17 +0000 Subject: [PATCH 3/3] add `AggressiveInlining` --- .../System.Private.CoreLib/src/System/IO/BinaryWriter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs index b69c0726c9b040..1eb469931f2dfd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Buffers.Binary; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; @@ -350,6 +351,7 @@ public virtual void Write(Half value) } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteBytes(T value) where T : unmanaged {