using System; using System.Buffers; using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Jobs; using Server; using Server.Network; namespace Benchmarks { [SimpleJob(RuntimeMoniker.NetCoreApp50)] public class BenchmarkPacketBroadcast { public static int SendUnicodeMessage( ArraySegment[] buffer, Serial serial, int graphic, MessageType type, int hue, int font, string lang, string name, string text ) { name = name?.Trim() ?? ""; text = text?.Trim() ?? ""; lang = lang?.Trim() ?? "ENU"; if (hue == 0) { hue = 0x3B2; } var writer = new CircularBufferWriter(buffer); writer.Write((byte)0xAE); writer.Write((ushort)(50 + text.Length * 2)); writer.Write(serial); writer.Write((short)graphic); writer.Write((byte)type); writer.Write((short)hue); writer.Write((short)font); writer.WriteAscii(lang, 4); writer.WriteAscii(name, 30); writer.WriteBigUniNull(text); return writer.Position; } public static int CreateUnicodeMessage( ref Span buffer, Serial serial, int graphic, MessageType type, int hue, int font, string lang, string name, string text ) { name = name?.Trim() ?? ""; text = text?.Trim() ?? ""; lang = lang?.Trim() ?? "ENU"; if (hue == 0) { hue = 0x3B2; } var writer = new SpanWriter(buffer); writer.Write((byte)0xAE); writer.Write((ushort)(50 + text.Length * 2)); writer.Write(serial); writer.Write((short)graphic); writer.Write((byte)type); writer.Write((short)hue); writer.Write((short)font); writer.WriteAscii(lang, 4); writer.WriteAscii(name, 30); writer.WriteBigUniNull(text); return writer.Position; } private Pipe[] _pipes = new Pipe[512]; private IntPtr[] _pointers = new IntPtr[512]; [IterationSetup] public void SetUp() { for (var i = 0; i < _pipes.Length; i++) { _pipes[i] = new Pipe(new byte[8192]); _pointers[i] = Marshal.AllocHGlobal(8192); } } [IterationCleanup] public void CleanUp() { for (var i = 0; i < _pipes.Length; i++) { _pipes[i] = null; Marshal.FreeHGlobal(_pointers[i]); } } [Benchmark] public int TestCircularBuffer() { var text = "This is some really long text that we want to handle. It should take a little bit to encode this."; foreach (var pipe in _pipes) { var result = pipe.Writer.TryGetMemory(); var length = SendUnicodeMessage( result.Buffer, Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, "ENU", "System", text ); pipe.Writer.Advance((uint)length); } return _pipes.Length; } [Benchmark] public int TestSpanWriterFromBuffer() { var text = "This is some really long text that we want to handle. It should take a little bit to encode this."; foreach (var pipe in _pipes) { var result = pipe.Writer.TryGetMemory(); Span buffer = result.Buffer[0]; var length = CreateUnicodeMessage( ref buffer, Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, "ENU", "System", text ); pipe.Writer.Advance((uint)length); } return _pipes.Length; } [Benchmark] public int TestSpanWriter() { var text = "This is some really long text that we want to handle. It should take a little bit to encode this."; Span buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(text)]; var length = CreateUnicodeMessage( ref buffer, Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, "ENU", "System", text ); buffer = buffer.Slice(0, length); foreach (var pipe in _pipes) { var result = pipe.Writer.TryGetMemory(); result.CopyFrom(buffer); pipe.Writer.Advance((uint)buffer.Length); } return _pipes.Length; } [Benchmark] public int TestSpanWriterAllocH() { var text = "This is some really long text that we want to handle. It should take a little bit to encode this."; foreach (var pointer in _pointers) { Span buffer; unsafe { buffer = new Span(pointer.ToPointer(), 8192); } CreateUnicodeMessage( ref buffer, Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, "ENU", "System", text ); } return _pipes.Length; } } }