diff --git a/Content.Benchmarks/NetSerializerIntBenchmark.cs b/Content.Benchmarks/NetSerializerIntBenchmark.cs new file mode 100644 index 0000000000..a111d98dbb --- /dev/null +++ b/Content.Benchmarks/NetSerializerIntBenchmark.cs @@ -0,0 +1,263 @@ +using System; +using System.Buffers.Binary; +using System.IO; +using BenchmarkDotNet.Attributes; + +namespace Content.Benchmarks +{ + [SimpleJob] + public class NetSerializerIntBenchmark + { + private MemoryStream _writeStream; + private MemoryStream _readStream; + private ushort _x16 = 5; + private uint _x32 = 5; + private ulong _x64 = 5; + private ushort _read16; + private uint _read32; + private ulong _read64; + + [GlobalSetup] + public void Setup() + { + _writeStream = new MemoryStream(64); + _readStream = new MemoryStream(); + _readStream.Write(new byte[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}); + } + + [Benchmark] + public void BenchWrite16Span() + { + _writeStream.Position = 0; + WriteUInt16Span(_writeStream, _x16); + } + + [Benchmark] + public void BenchWrite32Span() + { + _writeStream.Position = 0; + WriteUInt32Span(_writeStream, _x32); + } + + [Benchmark] + public void BenchWrite64Span() + { + _writeStream.Position = 0; + WriteUInt64Span(_writeStream, _x64); + } + + [Benchmark] + public void BenchRead16Span() + { + _readStream.Position = 0; + _read16 = ReadUInt16Span(_readStream); + } + + [Benchmark] + public void BenchRead32Span() + { + _readStream.Position = 0; + _read32 = ReadUInt32Span(_readStream); + } + + [Benchmark] + public void BenchRead64Span() + { + _readStream.Position = 0; + _read64 = ReadUInt64Span(_readStream); + } + + [Benchmark] + public void BenchWrite16Byte() + { + _writeStream.Position = 0; + WriteUInt16Byte(_writeStream, _x16); + } + + [Benchmark] + public void BenchWrite32Byte() + { + _writeStream.Position = 0; + WriteUInt32Byte(_writeStream, _x32); + } + + [Benchmark] + public void BenchWrite64Byte() + { + _writeStream.Position = 0; + WriteUInt64Byte(_writeStream, _x64); + } + + [Benchmark] + public void BenchRead16Byte() + { + _readStream.Position = 0; + _read16 = ReadUInt16Byte(_readStream); + } + [Benchmark] + public void BenchRead32Byte() + { + _readStream.Position = 0; + _read32 = ReadUInt32Byte(_readStream); + } + + [Benchmark] + public void BenchRead64Byte() + { + _readStream.Position = 0; + _read64 = ReadUInt64Byte(_readStream); + } + + private static void WriteUInt16Byte(Stream stream, ushort value) + { + stream.WriteByte((byte) value); + stream.WriteByte((byte) (value >> 8)); + } + + private static void WriteUInt32Byte(Stream stream, uint value) + { + stream.WriteByte((byte) value); + stream.WriteByte((byte) (value >> 8)); + stream.WriteByte((byte) (value >> 16)); + stream.WriteByte((byte) (value >> 24)); + } + + private static void WriteUInt64Byte(Stream stream, ulong value) + { + stream.WriteByte((byte) value); + stream.WriteByte((byte) (value >> 8)); + stream.WriteByte((byte) (value >> 16)); + stream.WriteByte((byte) (value >> 24)); + stream.WriteByte((byte) (value >> 32)); + stream.WriteByte((byte) (value >> 40)); + stream.WriteByte((byte) (value >> 48)); + stream.WriteByte((byte) (value >> 56)); + } + + private static ushort ReadUInt16Byte(Stream stream) + { + ushort a = 0; + + for (var i = 0; i < 16; i += 8) + { + var val = stream.ReadByte(); + if (val == -1) + throw new EndOfStreamException(); + + a |= (ushort) (val << i); + } + + return a; + } + + private static uint ReadUInt32Byte(Stream stream) + { + uint a = 0; + + for (var i = 0; i < 32; i += 8) + { + var val = stream.ReadByte(); + if (val == -1) + throw new EndOfStreamException(); + + a |= (uint) (val << i); + } + + return a; + } + + private static ulong ReadUInt64Byte(Stream stream) + { + ulong a = 0; + + for (var i = 0; i < 64; i += 8) + { + var val = stream.ReadByte(); + if (val == -1) + throw new EndOfStreamException(); + + a |= (ulong) (val << i); + } + + return a; + } + + private static void WriteUInt16Span(Stream stream, ushort value) + { + Span buf = stackalloc byte[2]; + BinaryPrimitives.WriteUInt16LittleEndian(buf, value); + + stream.Write(buf); + } + + private static void WriteUInt32Span(Stream stream, uint value) + { + Span buf = stackalloc byte[4]; + BinaryPrimitives.WriteUInt32LittleEndian(buf, value); + + stream.Write(buf); + } + + private static void WriteUInt64Span(Stream stream, ulong value) + { + Span buf = stackalloc byte[8]; + BinaryPrimitives.WriteUInt64LittleEndian(buf, value); + + stream.Write(buf); + } + + private static ushort ReadUInt16Span(Stream stream) + { + Span buf = stackalloc byte[2]; + var wSpan = buf; + + while (true) + { + var read = stream.Read(wSpan); + if (read == 0) + throw new EndOfStreamException(); + if (read == wSpan.Length) + break; + wSpan = wSpan[read..]; + } + + return BinaryPrimitives.ReadUInt16LittleEndian(buf); + } + + private static uint ReadUInt32Span(Stream stream) + { + Span buf = stackalloc byte[4]; + var wSpan = buf; + + while (true) + { + var read = stream.Read(wSpan); + if (read == 0) + throw new EndOfStreamException(); + if (read == wSpan.Length) + break; + wSpan = wSpan[read..]; + } + + return BinaryPrimitives.ReadUInt32LittleEndian(buf); + } + + private static ulong ReadUInt64Span(Stream stream) + { + Span buf = stackalloc byte[8]; + var wSpan = buf; + + while (true) + { + var read = stream.Read(wSpan); + if (read == 0) + throw new EndOfStreamException(); + if (read == wSpan.Length) + break; + wSpan = wSpan[read..]; + } + + return BinaryPrimitives.ReadUInt64LittleEndian(buf); + } + } +}