serialization improves and benchmarks

This commit is contained in:
2025-07-27 23:46:54 +03:00
parent 6c55567d3f
commit 965c8eb823
13 changed files with 243 additions and 94 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ Console.WriteLine("End waiting");
var totalRequests = tasks.Sum(i => i.Result); var totalRequests = tasks.Sum(i => i.Result);
Console.WriteLine($"Total requests: {totalRequests:N0}"); Console.WriteLine($"Total requests: {totalRequests:N0}");
Console.WriteLine($"Results: {totalRequests / time.TotalSeconds:N} RPS"); 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<List<ILoadTest>> GetLoadEndpoints(int count) async Task<List<ILoadTest>> GetLoadEndpoints(int count)
{ {
+93
View File
@@ -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<byte> FlatEncoded;
private Memory<byte> 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;
}
}
+30 -37
View File
@@ -1,51 +1,44 @@
using System.Collections.Generic; // See https://aka.ms/new-console-template for more information
using System.Linq;
using BenchmarkDotNet.Attributes;
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<CborTest>();
public static class CborExtensions
{ {
class Program public static unsafe void WriteToCbor(this RequestId id, CborWriter writer)
{ {
static void Main(string[] args) Span<byte> span = stackalloc byte[16];
{ MemoryMarshal.Write(span, ref id);
// Console.WriteLine("Hello, World!"); writer.WriteByteString(span);
// var summary = BenchmarkRunner.Run<CollectionsSpeed>();
}
} }
public class CollectionsSpeed [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void WriteToCborInline(this RequestId id, CborWriter writer)
{ {
private const int N = 1000; Span<byte> span = stackalloc byte[16];
MemoryMarshal.Write(span, ref id);
private readonly List<int> _immutable; writer.WriteByteString(span);
private readonly int[] _array;
public CollectionsSpeed()
{
_array = Enumerable.Range(0, N).ToArray();
// _immutable = [.._array];
} }
[Benchmark] public static void WriteToDest(this RequestId id, Span<byte> destination)
public int DefaultArray()
{ {
var sum = 0; MemoryMarshal.Write(destination, ref id);
for (int i = 0; i < N; i++)
{
sum += _array[i];
}
return sum;
} }
[Benchmark] [MethodImpl(MethodImplOptions.AggressiveOptimization)]
public int ImmutableArray() public static unsafe void WriteToCborOpt(this RequestId id, CborWriter writer)
{ {
var sum = 0; Span<byte> span = stackalloc byte[16];
for (int i = 0; i < N; i++) MemoryMarshal.Write(span, ref id);
{ writer.WriteByteString(span);
sum += _immutable[i];
}
return sum;
}
} }
} }
+57
View File
@@ -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<byte> 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;
}
}
+14 -3
View File
@@ -2,13 +2,24 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netstandard2.1</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" /> <ProjectReference Include="..\mROA\mROA.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Formats.Cbor">
<HintPath>..\..\..\..\.nuget\packages\system.formats.cbor\9.0.7\lib\net9.0\System.Formats.Cbor.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+19
View File
@@ -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<byte> span = stackalloc byte[16];
MemoryMarshal.Write(span, ref id);
writer.WriteByteString(span);
}
}
}
+6 -11
View File
@@ -18,7 +18,7 @@ namespace mROA.Cbor
private readonly IOrdinaryStructureParser[] _parsers = private readonly IOrdinaryStructureParser[] _parsers =
{ {
new NetworkMessageHeaderParser(), new DefaultCallRequestParser(), new FinalCommandExecutionParser(), new DefaultCallRequestParser(), new FinalCommandExecutionParser(),
new FinalCommandExecutionResultlessParser() new FinalCommandExecutionResultlessParser()
}; };
@@ -27,27 +27,21 @@ namespace mROA.Cbor
private bool FindParser(Type t, out IOrdinaryStructureParser parser) private bool FindParser(Type t, out IOrdinaryStructureParser parser)
{ {
if (t == typeof(NetworkMessage)) if (t == typeof(DefaultCallRequest))
{ {
parser = _parsers[0]; parser = _parsers[0];
return true; return true;
} }
if (t == typeof(DefaultCallRequest)) if (t == typeof(FinalCommandExecution<object>))
{ {
parser = _parsers[1]; parser = _parsers[1];
return true; return true;
} }
if (t == typeof(FinalCommandExecution<object>))
{
parser = _parsers[2];
return true;
}
if (t == typeof(FinalCommandExecution)) if (t == typeof(FinalCommandExecution))
{ {
parser = _parsers[3]; parser = _parsers[2];
return true; return true;
} }
@@ -165,7 +159,8 @@ namespace mROA.Cbor
writer.WriteDateTimeOffset(dto); writer.WriteDateTimeOffset(dto);
break; break;
case RequestId g: case RequestId g:
writer.WriteByteString(g.ToByteArray()); // writer.WriteByteString(g.ToByteArray());
g.WriteToCborInline(writer);
break; break;
case byte[] bytes: case byte[] bytes:
writer.WriteByteString(bytes); writer.WriteByteString(bytes);
+6 -28
View File
@@ -12,38 +12,14 @@ namespace mROA.Cbor
object Read(CborReader reader, IEndPointContext context, CborSerializationToolkit serialization); 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 class DefaultCallRequestParser : IOrdinaryStructureParser
{ {
public void Write(CborWriter writer, object value, IEndPointContext context, CborSerializationToolkit serialization) public void Write(CborWriter writer, object value, IEndPointContext context, CborSerializationToolkit serialization)
{ {
var v = (DefaultCallRequest)value; var v = (DefaultCallRequest)value;
writer.WriteStartArray(4); writer.WriteStartArray(4);
writer.WriteByteString(v.Id.ToByteArray()); v.Id.WriteToCborInline(writer);
// writer.WriteByteString(v.Id.ToByteArray());
writer.WriteInt32(v.CommandId); writer.WriteInt32(v.CommandId);
writer.WriteStartArray(1); writer.WriteStartArray(1);
writer.WriteUInt64(v.ObjectId.Flat); writer.WriteUInt64(v.ObjectId.Flat);
@@ -92,7 +68,8 @@ namespace mROA.Cbor
{ {
var v = (FinalCommandExecution<object>)value; var v = (FinalCommandExecution<object>)value;
writer.WriteStartArray(2); writer.WriteStartArray(2);
writer.WriteByteString(v.Id.ToByteArray()); // writer.WriteByteString(v.Id.ToByteArray());
v.Id.WriteToCborInline(writer);
serialization.WriteData(v.Result, writer, context); serialization.WriteData(v.Result, writer, context);
writer.WriteEndArray(); writer.WriteEndArray();
} }
@@ -116,7 +93,8 @@ namespace mROA.Cbor
{ {
var v = (FinalCommandExecution)value; var v = (FinalCommandExecution)value;
writer.WriteStartArray(1); writer.WriteStartArray(1);
writer.WriteByteString(v.Id.ToByteArray()); // writer.WriteByteString(v.Id.ToByteArray());
v.Id.WriteToCborInline(writer);
writer.WriteEndArray(); writer.WriteEndArray();
} }
+1
View File
@@ -7,6 +7,7 @@
<Version>2.0.7</Version> <Version>2.0.7</Version>
<LangVersion>9</LangVersion> <LangVersion>9</LangVersion>
<PackageIcon>mroaLogo.png</PackageIcon> <PackageIcon>mroaLogo.png</PackageIcon>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+6 -6
View File
@@ -17,8 +17,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Shared", "Example.S
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Frontend", "Example.Frontend\Example.Frontend.csproj", "{9BD25A13-3165-47C0-9EAA-5C59EC490E32}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Frontend", "Example.Frontend\Example.Frontend.csproj", "{9BD25A13-3165-47C0-9EAA-5C59EC490E32}"
EndProject 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}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Cbor", "mROA.Cbor\mROA.Cbor.csproj", "{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TotalDemo", "TotalDemo", "{FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}" 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 EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{8C20901F-B416-4ABC-8AA4-9059646B081B}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{8C20901F-B416-4ABC-8AA4-9059646B081B}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benchmark\mROA.Benchmark.csproj", "{E021E8B3-56C2-400E-A05E-523CF7831189}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{9BD25A13-3165-47C0-9EAA-5C59EC490E32}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Debug|Any CPU.Build.0 = 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 {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}.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.ActiveCfg = Release|Any CPU
{D9D28596-E10C-4A98-A2AA-573219467506}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -168,7 +168,7 @@ namespace mROA.Implementation.Backend
if (invoker.IsTrusted) if (invoker.IsTrusted)
representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, representationModule.PostCallMessageAsync(command.Id, EMessageType.FinishedCommandExecution,
payload, context); payload, context);
}); });
@@ -197,7 +197,7 @@ namespace mROA.Implementation.Backend
}; };
_cancellationRepo.FreeCancellation(command.Id); _cancellationRepo.FreeCancellation(command.Id);
representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, representationModule.PostCallMessageAsync(command.Id, EMessageType.FinishedCommandExecution,
payload, context); payload, context);
}); });
@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using mROA.Abstract; using mROA.Abstract;
namespace mROA.Implementation.Backend namespace mROA.Implementation.Backend
+3 -2
View File
@@ -35,7 +35,8 @@ namespace mROA.Implementation
public EMessageType MessageType { get; set; } public EMessageType MessageType { get; set; }
public byte[] Data { get; set; } public byte[] Data { get; set; }
public object Serialized { get; set; }
public IEndPointContext Context { get; set; }
public override string ToString() public override string ToString()
{ {
return $" {Id}:{MessageType} [{Data.Length}]"; return $" {Id}:{MessageType} [{Data.Length}]";
@@ -57,7 +58,7 @@ namespace mROA.Implementation
public ushort BodyLength; public ushort BodyLength;
public byte Type; public byte Type;
public NetworkMessage ToMessage(ReadOnlySpan<byte> memory) public NetworkMessage ToMessage(Span<byte> memory)
{ {
var data = memory[19..][..BodyLength]; var data = memory[19..][..BodyLength];
return new NetworkMessage return new NetworkMessage