diff --git a/Example.Load/Program.cs b/Example.Load/Program.cs index a0d0b94..280f5a4 100644 --- a/Example.Load/Program.cs +++ b/Example.Load/Program.cs @@ -31,7 +31,7 @@ Console.WriteLine("End waiting"); var totalRequests = tasks.Sum(i => i.Result); Console.WriteLine($"Total requests: {totalRequests:N0}"); Console.WriteLine($"Results: {totalRequests / time.TotalSeconds:N} RPS"); -File.AppendAllText("results.txt", $"[HEADER REMAKE] {totalRequests}\r\n"); +File.AppendAllText("results.txt", $"[FAST ID] {totalRequests}\r\n"); async Task> GetLoadEndpoints(int count) { diff --git a/mROA.Benchmark/CborTest.cs b/mROA.Benchmark/CborTest.cs new file mode 100644 index 0000000..d66ba1e --- /dev/null +++ b/mROA.Benchmark/CborTest.cs @@ -0,0 +1,93 @@ +using System.Formats.Cbor; +using BenchmarkDotNet.Attributes; + +namespace mROA.Benchmark; + + +[MemoryDiagnoser] +public class CborTest +{ + private CborWriter _writer; + private CborReader _reader; + + private Memory FlatEncoded; + private Memory ArrayEncoded; + public CborTest() + { + _writer = new CborWriter(initialCapacity:512); + + _writer.WriteStartArray(2); + _writer.WriteByteString([1, 2, 3, 4, 5, 6, 7, 8]); + _writer.WriteStartArray(2); + _writer.WriteInt32(12); + _writer.WriteTextString("tralala"); + _writer.WriteEndArray(); + _writer.WriteEndArray(); + + ArrayEncoded = _writer.Encode(); + + _writer.Reset(); + + _writer.WriteStartArray(3); + _writer.WriteByteString([1, 2, 3, 4, 5, 6, 7, 8]); + _writer.WriteInt32(12); + _writer.WriteTextString("tralala"); + _writer.WriteEndArray(); + FlatEncoded = _writer.Encode(); + } + + [Benchmark] + public int FlatWrite() + { + _writer.Reset(); + _writer.WriteStartArray(3); + _writer.WriteByteString([1, 2, 3, 4, 5, 6, 7, 8]); + _writer.WriteInt32(12); + _writer.WriteTextString("tralala"); + _writer.WriteEndArray(); + var len = _writer.Encode(FlatEncoded.Span); + return len; + } + + [Benchmark] + public int ArrayWrite() + { + _writer.Reset(); + _writer.WriteStartArray(2); + _writer.WriteByteString([1, 2, 3, 4, 5, 6, 7, 8]); + _writer.WriteStartArray(2); + _writer.WriteInt32(12); + _writer.WriteTextString("tralala"); + _writer.WriteEndArray(); + _writer.WriteEndArray(); + var len = _writer.Encode(ArrayEncoded.Span); + return len; + } + [Benchmark] + public int FlatRead() + { + var reader = new CborReader(FlatEncoded); + reader.ReadStartArray(); + var arr = reader.ReadByteString(); + var i = reader.ReadInt32(); + var text = reader.ReadTextString(); + reader.ReadEndArray(); + + return arr.Length; + } + + [Benchmark] + public int ArrayRead() + { + var reader = new CborReader(ArrayEncoded); + reader.ReadStartArray(); + var arr = reader.ReadByteString(); + reader.ReadStartArray(); + var i = reader.ReadInt32(); + var text = reader.ReadTextString(); + reader.ReadEndArray(); + reader.ReadEndArray(); + + return arr.Length; + } +} \ No newline at end of file diff --git a/mROA.Benchmark/Program.cs b/mROA.Benchmark/Program.cs index 217a6d7..1f030d2 100644 --- a/mROA.Benchmark/Program.cs +++ b/mROA.Benchmark/Program.cs @@ -1,51 +1,44 @@ -using System.Collections.Generic; -using System.Linq; -using BenchmarkDotNet.Attributes; +// See https://aka.ms/new-console-template for more information -namespace mROA.Benchmark +using System.Formats.Cbor; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using BenchmarkDotNet.Running; +using mROA.Benchmark; +using mROA.Implementation; + +Console.WriteLine("Hello, World!"); +var test = new CborTest(); +test.ArrayWrite(); +BenchmarkRunner.Run(); + +public static class CborExtensions { - class Program + public static unsafe void WriteToCbor(this RequestId id, CborWriter writer) { - static void Main(string[] args) - { - // Console.WriteLine("Hello, World!"); - // var summary = BenchmarkRunner.Run(); - } + Span span = stackalloc byte[16]; + MemoryMarshal.Write(span, ref id); + writer.WriteByteString(span); } - public class CollectionsSpeed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteToCborInline(this RequestId id, CborWriter writer) { - private const int N = 1000; + Span span = stackalloc byte[16]; + MemoryMarshal.Write(span, ref id); + writer.WriteByteString(span); + } - private readonly List _immutable; - private readonly int[] _array; - - public CollectionsSpeed() - { - _array = Enumerable.Range(0, N).ToArray(); - // _immutable = [.._array]; - } - - [Benchmark] - public int DefaultArray() - { - var sum = 0; - for (int i = 0; i < N; i++) - { - sum += _array[i]; - } - return sum; - } + public static void WriteToDest(this RequestId id, Span destination) + { + MemoryMarshal.Write(destination, ref id); + } - [Benchmark] - public int ImmutableArray() - { - var sum = 0; - for (int i = 0; i < N; i++) - { - sum += _immutable[i]; - } - return sum; - } + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + public static unsafe void WriteToCborOpt(this RequestId id, CborWriter writer) + { + Span span = stackalloc byte[16]; + MemoryMarshal.Write(span, ref id); + writer.WriteByteString(span); } } \ No newline at end of file diff --git a/mROA.Benchmark/RequestWriter.cs b/mROA.Benchmark/RequestWriter.cs new file mode 100644 index 0000000..4ccd89f --- /dev/null +++ b/mROA.Benchmark/RequestWriter.cs @@ -0,0 +1,57 @@ +using System.Formats.Cbor; +using BenchmarkDotNet.Attributes; +using mROA.Implementation; + +[MemoryDiagnoser] +public class RequestWriter +{ + private const int N = 1000; + public RequestId Id = RequestId.Generate(); + private CborWriter _writer; + + public RequestWriter() + { + _writer = new CborWriter(initialCapacity: 512); + } + + [Benchmark(Baseline = true)] + public int DefaultCbor() + { + _writer.Reset(); + _writer.WriteByteString(Id.ToByteArray()); + return _writer.BytesWritten; + } + [Benchmark] + public int DirectCbor() + { + _writer.Reset(); + Id.WriteToCbor(_writer); + return _writer.BytesWritten; + } + + [Benchmark] + public int Stackalloc() + { + _writer.Reset(); + Span span = stackalloc byte[16]; + Id.WriteToDest(span); + _writer.WriteByteString(span); + return _writer.BytesWritten; + } + + [Benchmark] + public int DirectCborInline() + { + _writer.Reset(); + Id.WriteToCborInline(_writer); + return _writer.BytesWritten; + } + + [Benchmark] + public int DirectCborOpt() + { + _writer.Reset(); + Id.WriteToCborOpt(_writer); + return _writer.BytesWritten; + } +} \ No newline at end of file diff --git a/mROA.Benchmark/mROA.Benchmark.csproj b/mROA.Benchmark/mROA.Benchmark.csproj index 5697c66..a7f69a0 100644 --- a/mROA.Benchmark/mROA.Benchmark.csproj +++ b/mROA.Benchmark/mROA.Benchmark.csproj @@ -2,13 +2,24 @@ Exe - netstandard2.1 - + net9.0 + enable enable + true - + + + + + + ..\..\..\..\.nuget\packages\system.formats.cbor\9.0.7\lib\net9.0\System.Formats.Cbor.dll + + + + + diff --git a/mROA.Cbor/CborExtensions.cs b/mROA.Cbor/CborExtensions.cs new file mode 100644 index 0000000..1685ea3 --- /dev/null +++ b/mROA.Cbor/CborExtensions.cs @@ -0,0 +1,19 @@ +using System; +using System.Formats.Cbor; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using mROA.Implementation; + +namespace mROA.Cbor +{ + public static class CborExtensions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteToCborInline(this RequestId id, CborWriter writer) + { + Span span = stackalloc byte[16]; + MemoryMarshal.Write(span, ref id); + writer.WriteByteString(span); + } + } +} \ No newline at end of file diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 0506e65..4036166 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -18,7 +18,7 @@ namespace mROA.Cbor private readonly IOrdinaryStructureParser[] _parsers = { - new NetworkMessageHeaderParser(), new DefaultCallRequestParser(), new FinalCommandExecutionParser(), + new DefaultCallRequestParser(), new FinalCommandExecutionParser(), new FinalCommandExecutionResultlessParser() }; @@ -27,27 +27,21 @@ namespace mROA.Cbor private bool FindParser(Type t, out IOrdinaryStructureParser parser) { - if (t == typeof(NetworkMessage)) + if (t == typeof(DefaultCallRequest)) { parser = _parsers[0]; return true; } - if (t == typeof(DefaultCallRequest)) + if (t == typeof(FinalCommandExecution)) { parser = _parsers[1]; return true; } - if (t == typeof(FinalCommandExecution)) - { - parser = _parsers[2]; - return true; - } - if (t == typeof(FinalCommandExecution)) { - parser = _parsers[3]; + parser = _parsers[2]; return true; } @@ -165,7 +159,8 @@ namespace mROA.Cbor writer.WriteDateTimeOffset(dto); break; case RequestId g: - writer.WriteByteString(g.ToByteArray()); + // writer.WriteByteString(g.ToByteArray()); + g.WriteToCborInline(writer); break; case byte[] bytes: writer.WriteByteString(bytes); diff --git a/mROA.Cbor/IOrdinaryStructureParser.cs b/mROA.Cbor/IOrdinaryStructureParser.cs index 10ff38d..e39e8e0 100644 --- a/mROA.Cbor/IOrdinaryStructureParser.cs +++ b/mROA.Cbor/IOrdinaryStructureParser.cs @@ -12,38 +12,14 @@ namespace mROA.Cbor object Read(CborReader reader, IEndPointContext context, CborSerializationToolkit serialization); } - public class NetworkMessageHeaderParser : IOrdinaryStructureParser - { - public void Write(CborWriter writer, object value, IEndPointContext context, CborSerializationToolkit serialization) - { - var v = value as NetworkMessage; - writer.WriteStartArray(3); - writer.WriteByteString(v.Id.ToByteArray()); - writer.WriteInt32((int)v.MessageType); - writer.WriteByteString(v.Data); - writer.WriteEndArray(); - } - - public object Read(CborReader reader, IEndPointContext context, CborSerializationToolkit serialization) - { - reader.ReadStartArray(); - var value = new NetworkMessage - { - Id = new RequestId(reader.ReadByteString()), - MessageType = (EMessageType)reader.ReadInt32(), - Data = reader.ReadByteString() - }; - return value; - } - } - public class DefaultCallRequestParser : IOrdinaryStructureParser { public void Write(CborWriter writer, object value, IEndPointContext context, CborSerializationToolkit serialization) { var v = (DefaultCallRequest)value; writer.WriteStartArray(4); - writer.WriteByteString(v.Id.ToByteArray()); + v.Id.WriteToCborInline(writer); + // writer.WriteByteString(v.Id.ToByteArray()); writer.WriteInt32(v.CommandId); writer.WriteStartArray(1); writer.WriteUInt64(v.ObjectId.Flat); @@ -92,7 +68,8 @@ namespace mROA.Cbor { var v = (FinalCommandExecution)value; writer.WriteStartArray(2); - writer.WriteByteString(v.Id.ToByteArray()); + // writer.WriteByteString(v.Id.ToByteArray()); + v.Id.WriteToCborInline(writer); serialization.WriteData(v.Result, writer, context); writer.WriteEndArray(); } @@ -116,7 +93,8 @@ namespace mROA.Cbor { var v = (FinalCommandExecution)value; writer.WriteStartArray(1); - writer.WriteByteString(v.Id.ToByteArray()); + // writer.WriteByteString(v.Id.ToByteArray()); + v.Id.WriteToCborInline(writer); writer.WriteEndArray(); } diff --git a/mROA.Cbor/mROA.Cbor.csproj b/mROA.Cbor/mROA.Cbor.csproj index 53687e0..6fe99f0 100644 --- a/mROA.Cbor/mROA.Cbor.csproj +++ b/mROA.Cbor/mROA.Cbor.csproj @@ -7,6 +7,7 @@ 2.0.7 9 mroaLogo.png + true diff --git a/mROA.sln b/mROA.sln index b6d9335..97ede35 100644 --- a/mROA.sln +++ b/mROA.sln @@ -17,8 +17,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Shared", "Example.S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Frontend", "Example.Frontend\Example.Frontend.csproj", "{9BD25A13-3165-47C0-9EAA-5C59EC490E32}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benchmark\mROA.Benchmark.csproj", "{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Cbor", "mROA.Cbor\mROA.Cbor.csproj", "{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TotalDemo", "TotalDemo", "{FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}" @@ -31,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Functionality.Shared", "Fun EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{8C20901F-B416-4ABC-8AA4-9059646B081B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benchmark\mROA.Benchmark.csproj", "{E021E8B3-56C2-400E-A05E-523CF7831189}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -61,10 +61,6 @@ Global {9BD25A13-3165-47C0-9EAA-5C59EC490E32}.Debug|Any CPU.Build.0 = Debug|Any CPU {9BD25A13-3165-47C0-9EAA-5C59EC490E32}.Release|Any CPU.ActiveCfg = Release|Any CPU {9BD25A13-3165-47C0-9EAA-5C59EC490E32}.Release|Any CPU.Build.0 = Release|Any CPU - {6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Release|Any CPU.Build.0 = Release|Any CPU {6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Debug|Any CPU.Build.0 = Debug|Any CPU {6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -81,6 +77,10 @@ Global {D9D28596-E10C-4A98-A2AA-573219467506}.Debug|Any CPU.Build.0 = Debug|Any CPU {D9D28596-E10C-4A98-A2AA-573219467506}.Release|Any CPU.ActiveCfg = Release|Any CPU {D9D28596-E10C-4A98-A2AA-573219467506}.Release|Any CPU.Build.0 = Release|Any CPU + {E021E8B3-56C2-400E-A05E-523CF7831189}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E021E8B3-56C2-400E-A05E-523CF7831189}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E021E8B3-56C2-400E-A05E-523CF7831189}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E021E8B3-56C2-400E-A05E-523CF7831189}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index d72ec7c..53b8937 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -168,7 +168,7 @@ namespace mROA.Implementation.Backend if (invoker.IsTrusted) - representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, + representationModule.PostCallMessageAsync(command.Id, EMessageType.FinishedCommandExecution, payload, context); }); @@ -197,7 +197,7 @@ namespace mROA.Implementation.Backend }; _cancellationRepo.FreeCancellation(command.Id); - representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, + representationModule.PostCallMessageAsync(command.Id, EMessageType.FinishedCommandExecution, payload, context); }); diff --git a/mROA/Implementation/Backend/MultiClientInstanceRepository.cs b/mROA/Implementation/Backend/MultiClientInstanceRepository.cs index 0488e21..f5d6cd2 100644 --- a/mROA/Implementation/Backend/MultiClientInstanceRepository.cs +++ b/mROA/Implementation/Backend/MultiClientInstanceRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using mROA.Abstract; namespace mROA.Implementation.Backend diff --git a/mROA/Implementation/NetworkMessage.cs b/mROA/Implementation/NetworkMessage.cs index 3a7e5ed..719bd42 100644 --- a/mROA/Implementation/NetworkMessage.cs +++ b/mROA/Implementation/NetworkMessage.cs @@ -35,7 +35,8 @@ namespace mROA.Implementation public EMessageType MessageType { get; set; } public byte[] Data { get; set; } - + public object Serialized { get; set; } + public IEndPointContext Context { get; set; } public override string ToString() { return $" {Id}:{MessageType} [{Data.Length}]"; @@ -57,7 +58,7 @@ namespace mROA.Implementation public ushort BodyLength; public byte Type; - public NetworkMessage ToMessage(ReadOnlySpan memory) + public NetworkMessage ToMessage(Span memory) { var data = memory[19..][..BodyLength]; return new NetworkMessage