From 304811c964108eb09a86d2c3e828fc2cbcde1a54 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanow Date: Wed, 6 Aug 2025 14:32:48 +0300 Subject: [PATCH 1/2] Prepare for many parsers --- mROA.Benchmark/IdGeneration.cs | 37 ++++++++++++ mROA.Benchmark/Program.cs | 2 +- mROA.Benchmark/VirtualOverhead.cs | 57 +++++++++++++------ mROA.Cbor/CborSerializationToolkit.cs | 7 ++- .../IContextualSerializationToolKit.cs | 1 + .../CreativeRepresentationModuleProducer.cs | 1 - 6 files changed, 84 insertions(+), 21 deletions(-) create mode 100644 mROA.Benchmark/IdGeneration.cs diff --git a/mROA.Benchmark/IdGeneration.cs b/mROA.Benchmark/IdGeneration.cs new file mode 100644 index 0000000..1bd44be --- /dev/null +++ b/mROA.Benchmark/IdGeneration.cs @@ -0,0 +1,37 @@ +using BenchmarkDotNet.Attributes; +using mROA.Implementation; + +namespace mROA.Benchmark; + +public class IdGeneration +{ + public static int X = 0; + + [Benchmark] + public Guid GuidGeneration() + { + return Guid.NewGuid(); + } + + [Benchmark(Baseline = true)] + public RequestId ReqIdGeneration() + { + return RequestId.Generate(); + } + + [Benchmark] + public RequestId ReqIdIfGeneration() + { + var reqId = RequestId.Generate(); + if (++X % 2 == 0) + { + reqId.P0 = 0; + } + else + { + reqId.P1 = 0; + } + return reqId; + + } +} \ No newline at end of file diff --git a/mROA.Benchmark/Program.cs b/mROA.Benchmark/Program.cs index 9bdbec5..2f65d73 100644 --- a/mROA.Benchmark/Program.cs +++ b/mROA.Benchmark/Program.cs @@ -10,7 +10,7 @@ using mROA.Implementation; Console.WriteLine("Hello, World!"); var test = new CborTest(); test.ArrayWrite(); -BenchmarkRunner.Run(); +BenchmarkRunner.Run(); public static class CborExtensions { diff --git a/mROA.Benchmark/VirtualOverhead.cs b/mROA.Benchmark/VirtualOverhead.cs index 13dac79..fea1854 100644 --- a/mROA.Benchmark/VirtualOverhead.cs +++ b/mROA.Benchmark/VirtualOverhead.cs @@ -1,3 +1,4 @@ +using System.Runtime.CompilerServices; using BenchmarkDotNet.Attributes; using mROA.Implementation; @@ -5,17 +6,15 @@ namespace mROA.Benchmark; public class VirtualOverhead { - private ICallRequest _request; private CallRequest _directRequest; private RawCallRequest _rawRequest; - - public VirtualOverhead() - { - _request = new CallRequest + + [GlobalSetup] + public void Setup() { + _directRequest = new CallRequest { CommandId = 5, Id = new RequestId(), ObjectId = ComplexObjectIdentifier.Null, Parameters = null }; - _directRequest = (CallRequest)_request; _rawRequest = new RawCallRequest { CommandId = _directRequest.CommandId, Id = _directRequest.Id, ObjectId = _directRequest.ObjectId, @@ -24,18 +23,6 @@ public class VirtualOverhead } [Benchmark(Baseline = true)] - public long VirtualUsage() - { - var req = _request; - long acc = 0; - acc += req.CommandId; - acc += (long)(req.Id.P1 + req.Id.P0); - acc += req.ObjectId.ContextId + req.ObjectId.OwnerId; - acc += (req.Parameters ?? []).Length; - return acc; - } - - [Benchmark] public long DirectUsage() { var req = _directRequest; @@ -58,6 +45,40 @@ public class VirtualOverhead acc += (req.Parameters ?? []).Length; return acc; } + + [Benchmark] + public long ParamUsage() + { + return Call(_directRequest); + } + + [Benchmark] + public long ParamInUsage() + { + return CallIn(in _directRequest); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public long Call(CallRequest req) + { + long acc = 0; + acc += req.CommandId; + acc += (long)(req.Id.P1 + req.Id.P0); + acc += req.ObjectId.ContextId + req.ObjectId.OwnerId; + acc += (req.Parameters ?? []).Length; + return acc; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public long CallIn(in CallRequest req) + { + long acc = 0; + acc += req.CommandId; + acc += (long)(req.Id.P1 + req.Id.P0); + acc += req.ObjectId.ContextId + req.ObjectId.OwnerId; + acc += (req.Parameters ?? []).Length; + return acc; + } } public struct RawCallRequest diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 69f8a59..3005cb9 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -14,7 +14,7 @@ namespace mROA.Cbor { public class CborSerializationToolkit : IContextualSerializationToolKit { - private readonly CborWriter _writer = new(initialCapacity: 512); + private readonly CborWriter _writer = new(initialCapacity: 2048); private readonly IOrdinaryStructureParser[] _parsers = { @@ -118,6 +118,11 @@ namespace mROA.Cbor return Convert.ChangeType(nonCasted, type); } + public IContextualSerializationToolKit Clone() + { + return new CborSerializationToolkit(); + } + public void WriteData(object? obj, CborWriter writer, IEndPointContext? context) { if (obj is not null && FindParser(obj.GetType(), out var parser)) diff --git a/mROA/Abstract/IContextualSerializationToolKit.cs b/mROA/Abstract/IContextualSerializationToolKit.cs index ebf604c..a394e2c 100644 --- a/mROA/Abstract/IContextualSerializationToolKit.cs +++ b/mROA/Abstract/IContextualSerializationToolKit.cs @@ -10,5 +10,6 @@ namespace mROA.Abstract object? Deserialize(byte[] rawData, Type type, IEndPointContext? context); T Deserialize(ReadOnlyMemory rawMemory, IEndPointContext? context); object? Cast(object? nonCasted, Type type, IEndPointContext? context); + IContextualSerializationToolKit Clone(); } } \ No newline at end of file diff --git a/mROA/Implementation/CreativeRepresentationModuleProducer.cs b/mROA/Implementation/CreativeRepresentationModuleProducer.cs index cfd2cb1..44204ae 100644 --- a/mROA/Implementation/CreativeRepresentationModuleProducer.cs +++ b/mROA/Implementation/CreativeRepresentationModuleProducer.cs @@ -13,7 +13,6 @@ namespace mROA.Implementation _serialization = serialization; } - public IRepresentationModule Produce(int id) { var interaction = _hub.GetInteraction(id); From fd971cdecc97fade228fd6c8e5c11174a109bf6b Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanow Date: Wed, 6 Aug 2025 19:16:10 +0300 Subject: [PATCH 2/2] Clone serialization toolkit for each user --- mROA.Benchmark/CborExtensions.cs | 35 +++++++++++++++++ mROA.Benchmark/Program.cs | 38 +------------------ .../Backend/HubRequestExtractor.cs | 8 ++-- .../Backend/NetworkGatewayModule.cs | 2 +- .../CreativeRepresentationModuleProducer.cs | 2 +- 5 files changed, 42 insertions(+), 43 deletions(-) create mode 100644 mROA.Benchmark/CborExtensions.cs diff --git a/mROA.Benchmark/CborExtensions.cs b/mROA.Benchmark/CborExtensions.cs new file mode 100644 index 0000000..6f5150b --- /dev/null +++ b/mROA.Benchmark/CborExtensions.cs @@ -0,0 +1,35 @@ +using System.Formats.Cbor; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using mROA.Implementation; + +public static class CborExtensions +{ + public static unsafe void WriteToCbor(this RequestId id, CborWriter writer) + { + Span span = stackalloc byte[16]; + MemoryMarshal.Write(span, ref id); + writer.WriteByteString(span); + } + + [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); + } + + public static void WriteToDest(this RequestId id, Span destination) + { + MemoryMarshal.Write(destination, ref id); + } + + [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/Program.cs b/mROA.Benchmark/Program.cs index 2f65d73..560812c 100644 --- a/mROA.Benchmark/Program.cs +++ b/mROA.Benchmark/Program.cs @@ -1,44 +1,8 @@ // See https://aka.ms/new-console-template for more information -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 -{ - public static unsafe void WriteToCbor(this RequestId id, CborWriter writer) - { - Span span = stackalloc byte[16]; - MemoryMarshal.Write(span, ref id); - writer.WriteByteString(span); - } - - [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); - } - - public static void WriteToDest(this RequestId id, Span destination) - { - MemoryMarshal.Write(destination, ref id); - } - - [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 +BenchmarkRunner.Run(); \ No newline at end of file diff --git a/mROA/Implementation/Backend/HubRequestExtractor.cs b/mROA/Implementation/Backend/HubRequestExtractor.cs index a7f27f5..c4438ab 100644 --- a/mROA/Implementation/Backend/HubRequestExtractor.cs +++ b/mROA/Implementation/Backend/HubRequestExtractor.cs @@ -25,15 +25,15 @@ namespace mROA.Implementation.Backend public IRequestExtractor this[int id] => _producedExtractors[id]; - public IRequestExtractor HubOnOnConnected(IRepresentationModule interaction) + public IRequestExtractor HubOnOnConnected(IRepresentationModule representationModule) { - var extractor = CreateExtractor(interaction); + var extractor = CreateExtractor(representationModule); if (_mode.DistributionType == EDistributionType.Channeled) { - extractor.StartExtraction().ContinueWith(_ => OnDisconnected(interaction)); + extractor.StartExtraction().ContinueWith(_ => OnDisconnected(representationModule)); } - _producedExtractors[interaction.Id] = extractor; + _producedExtractors[representationModule.Id] = extractor; return extractor; } diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index f14f19f..27d62a0 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -106,7 +106,7 @@ namespace mROA.Implementation.Backend _extractorsTokenSources[interaction.ConnectionId] = cts; _hub.RegisterInteraction(interaction); - var requestExtractor = _hre.HubOnOnConnected(new RepresentationModule(interaction, _serialization)); + var requestExtractor = _hre.HubOnOnConnected(new RepresentationModule(interaction, _serialization.Clone())); if (_distribution.DistributionType != EDistributionType.Channeled) { diff --git a/mROA/Implementation/CreativeRepresentationModuleProducer.cs b/mROA/Implementation/CreativeRepresentationModuleProducer.cs index 44204ae..72be897 100644 --- a/mROA/Implementation/CreativeRepresentationModuleProducer.cs +++ b/mROA/Implementation/CreativeRepresentationModuleProducer.cs @@ -17,7 +17,7 @@ namespace mROA.Implementation { var interaction = _hub.GetInteraction(id); - var produced = new RepresentationModule(interaction, _serialization); + var produced = new RepresentationModule(interaction, _serialization.Clone()); return produced; }