Skip to content

Commit

Permalink
Benchmark work and performance tuning of serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
halgari committed Jan 10, 2024
1 parent e093328 commit 09c492c
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 38 deletions.
17 changes: 14 additions & 3 deletions benchmarks/NexusMods.EventSourcing.Benchmarks/ABenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using NexusMods.EventSourcing.Abstractions;
using NexusMods.EventSourcing.RocksDB;
using NexusMods.EventSourcing.Serialization;
using NexusMods.EventSourcing.TestModel;
using NexusMods.Paths;

namespace NexusMods.EventSourcing.Benchmarks;

Expand All @@ -27,11 +30,19 @@ public ABenchmark()

public void MakeStore(Type type)
{
var serializer = Services.GetRequiredService<EventSerializer>();
var serializer = Services.GetRequiredService<BinaryEventSerializer>();
IEventStore eventStore;
if (type == typeof(InMemoryEventStore<EventSerializer>))
if (type == typeof(InMemoryEventStore<BinaryEventSerializer>))
{
eventStore = new InMemoryEventStore<EventSerializer>(serializer);
eventStore = new InMemoryEventStore<BinaryEventSerializer>(serializer);
}
else if (type == typeof(RocksDBEventStore<BinaryEventSerializer>))
{
eventStore = new RocksDBEventStore<BinaryEventSerializer>(serializer,
new RocksDB.Settings
{
StorageLocation = FileSystem.Shared.GetKnownPath(KnownPath.EntryDirectory).Combine("FasterKV.EventStore" + Guid.NewGuid())
});
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using BenchmarkDotNet.Attributes;
using NexusMods.EventSourcing.Abstractions;
using NexusMods.EventSourcing.Serialization;
using NexusMods.EventSourcing.TestModel;
using NexusMods.EventSourcing.TestModel.Events;
using NexusMods.EventSourcing.TestModel.Model;
Expand All @@ -15,10 +16,11 @@ public class AccumulatorBenchmarks : ABenchmark
private readonly EntityContext _ctx;
private readonly LoadoutRegistry _registry;
private readonly Loadout[] _loadouts;
private readonly int _numLoadouts;

public AccumulatorBenchmarks()
{
MakeStore(typeof(InMemoryEventStore<EventSerializer>));
MakeStore(typeof(InMemoryEventStore<BinaryEventSerializer>));

_ctx = new EntityContext(EventStore);
_ctx.Add(new CreateLoadout(EntityId<Loadout>.NewId(), "Test"));
Expand All @@ -29,12 +31,18 @@ public AccumulatorBenchmarks()
throw new Exception("Bad state");

_loadouts = _registry.Loadouts.ToArray();
_numLoadouts = _loadouts.Length;

}

[Benchmark]
public string GetMultiAttributeItems()
public int GetMultiAttributeItems()
{
return _loadouts[0].Name;
var size = 0;
for (var j = 0; j < 10_000_000; j++)
{
size += _loadouts[0].Name.Length;
}
return size;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using BenchmarkDotNet.Attributes;
using NexusMods.EventSourcing.Abstractions;
using NexusMods.EventSourcing.RocksDB;
using NexusMods.EventSourcing.Serialization;
using NexusMods.EventSourcing.TestModel;
using NexusMods.EventSourcing.TestModel.Events;
using NexusMods.EventSourcing.TestModel.Model;
Expand All @@ -15,10 +16,10 @@ public class EntityContextBenchmarks : ABenchmark
private EntityId<Loadout>[] _ids = Array.Empty<EntityId<Loadout>>();
private EntityContext _context = null!;

[Params(typeof(InMemoryEventStore<EventSerializer>),
//typeof(FasterKVEventStore<EventSerializer>),
typeof(RocksDBEventStore<EventSerializer>))]
public Type EventStoreType { get; set; } = typeof(InMemoryEventStore<EventSerializer>);
[Params(typeof(InMemoryEventStore<BinaryEventSerializer>),
//typeof(FasterKVEventStore<BinaryEventSerializer>),
typeof(RocksDBEventStore<BinaryEventSerializer>))]
public Type EventStoreType { get; set; } = typeof(InMemoryEventStore<BinaryEventSerializer>);

[Params(100, 1000)]
public int EventCount { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Extensions.Logging;
using NexusMods.EventSourcing.Abstractions;
using NexusMods.EventSourcing.RocksDB;
using NexusMods.EventSourcing.Serialization;
using NexusMods.EventSourcing.TestModel;
using NexusMods.EventSourcing.TestModel.Events;
using NexusMods.EventSourcing.TestModel.Model;
Expand All @@ -29,9 +30,9 @@ public EventStoreBenchmarks()
}


[Params(typeof(InMemoryEventStore<EventSerializer>),
//typeof(FasterKVEventStore<EventSerializer>),
typeof(RocksDBEventStore<EventSerializer>))]
[Params(typeof(InMemoryEventStore<BinaryEventSerializer>),
//typeof(FasterKVEventStore<BinaryEventSerializer>),
typeof(RocksDBEventStore<BinaryEventSerializer>))]
public Type EventStoreType { get; set; } = null!;

[GlobalSetup]
Expand Down
16 changes: 14 additions & 2 deletions benchmarks/NexusMods.EventSourcing.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
using BenchmarkDotNet.Running;
using NexusMods.EventSourcing.Benchmarks;
using NexusMods.EventSourcing.RocksDB;
using NexusMods.EventSourcing.Serialization;
using NexusMods.EventSourcing.TestModel;


/*
#if DEBUG
var readBenchmarks = new EntityContextBenchmarks();
readBenchmarks.EventStoreType = typeof(RocksDBEventStore<EventSerializer>);
readBenchmarks.EventStoreType = typeof(RocksDBEventStore<BinaryEventSerializer>);
readBenchmarks.EventCount = 1000;
readBenchmarks.EntityCount = 1000;
Console.WriteLine("Setup");
Expand All @@ -18,10 +20,11 @@
readBenchmarks.LoadAllEntities();
Console.WriteLine("LoadAllEntities done");
#else
BenchmarkRunner.Run<EventStoreBenchmarks>();
BenchmarkRunner.Run<EntityContextBenchmarks>();
#endif
*/


#if DEBUG
var benchmarks = new AccumulatorBenchmarks();
for (int i = 0; i < 10_000_000; i++)
Expand All @@ -32,3 +35,12 @@
#else
BenchmarkRunner.Run<AccumulatorBenchmarks>();
#endif

/*
| Method | Mean | Error | StdDev | Gen0 | Allocated |
|------------ |---------:|--------:|--------:|-------:|----------:|
| Serialize | 174.2 ns | 0.42 ns | 0.37 ns | - | - |
| Deserialize | 133.7 ns | 0.80 ns | 0.75 ns | 0.0312 | 592 B |
*/
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using BenchmarkDotNet.Attributes;
using NexusMods.EventSourcing.Abstractions;
using NexusMods.EventSourcing.RocksDB;
using NexusMods.EventSourcing.Serialization;
using NexusMods.EventSourcing.TestModel;
using NexusMods.EventSourcing.TestModel.Events;
using NexusMods.EventSourcing.TestModel.Model;
Expand All @@ -13,10 +14,10 @@ public class ReadBenchmarks : ABenchmark
{
private EntityId<Loadout>[] _ids = Array.Empty<EntityId<Loadout>>();

[Params(typeof(InMemoryEventStore<EventSerializer>),
//typeof(FasterKVEventStore<EventSerializer>),
typeof(RocksDBEventStore<EventSerializer>))]
public Type EventStoreType { get; set; } = typeof(InMemoryEventStore<EventSerializer>);
[Params(typeof(InMemoryEventStore<BinaryEventSerializer>),
//typeof(FasterKVEventStore<BinaryEventSerializer>),
typeof(RocksDBEventStore<BinaryEventSerializer>))]
public Type EventStoreType { get; set; } = typeof(InMemoryEventStore<BinaryEventSerializer>);

[Params(100, 1000)]
public int EventCount { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using BenchmarkDotNet.Attributes;
using Microsoft.Extensions.DependencyInjection;
using NexusMods.EventSourcing.Abstractions;
using NexusMods.EventSourcing.Serialization;
using NexusMods.EventSourcing.TestModel.Events;
using NexusMods.EventSourcing.TestModel.Model;

namespace NexusMods.EventSourcing.Benchmarks;

[MemoryDiagnoser]
public class SerializationBenchmarks : ABenchmark
{
private readonly IEvent[] _events;
private BinaryEventSerializer _serializer = null!;
private byte[][] _serializedEvents = null!;

public SerializationBenchmarks()
{
_events =
[
new CreateLoadout(EntityId<Loadout>.NewId(), "Test"),
new RenameLoadout(EntityId<Loadout>.NewId(), "Test"),
new AddMod("New Mod", true, EntityId<Mod>.NewId(), new EntityId<Loadout>()),
new AddCollection(EntityId<Collection>.NewId(), "NewCollection", EntityId<Loadout>.NewId(),
[EntityId<Mod>.NewId()]),
new DeleteMod(EntityId<Mod>.NewId(), EntityId<Loadout>.NewId()),
new RenameLoadout(EntityId<Loadout>.NewId(), "Test"),
new SwapModEnabled(EntityId<Mod>.NewId(), true)
];
}

[GlobalSetup]
public void Setup()
{
_serializer = Services.GetRequiredService<BinaryEventSerializer>();

_serializedEvents = _events.Select(evnt => _serializer.Serialize(evnt).ToArray()).ToArray();
}

[Benchmark]
public int Serialize()
{
var size = 0;
for (var i = 0; i < _events.Length; i++)
{
var evnt = _events[i];
size += _serializer.Serialize(evnt).Length;
}

return size;
}

[Benchmark]
public int Deserialize()
{
var size = 0;
for (var i = 0; i < _serializedEvents.Length; i++)
{
var evnt = _serializedEvents[i];
_serializer.Deserialize(evnt);
size += 1;
}
return size;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Extensions.Hosting;
using NexusMods.EventSourcing.Abstractions;
using NexusMods.EventSourcing.RocksDB;
using NexusMods.EventSourcing.Serialization;
using NexusMods.EventSourcing.TestModel;
using NexusMods.EventSourcing.TestModel.Events;
using NexusMods.EventSourcing.TestModel.Model;
Expand All @@ -16,10 +17,10 @@ public class WriteBenchmarks : ABenchmark
{
private readonly IEvent[] _events;

[Params(typeof(InMemoryEventStore<EventSerializer>),
//typeof(FasterKVEventStore<EventSerializer>),
typeof(RocksDBEventStore<EventSerializer>))]
public Type EventStoreType { get; set; } = typeof(InMemoryEventStore<EventSerializer>);
[Params(typeof(InMemoryEventStore<BinaryEventSerializer>),
//typeof(FasterKVEventStore<BinaryEventSerializer>),
typeof(RocksDBEventStore<BinaryEventSerializer>))]
public Type EventStoreType { get; set; } = typeof(InMemoryEventStore<BinaryEventSerializer>);

[Params(100, 1000, 10000)]
public int EventCount { get; set; } = 100;
Expand Down
36 changes: 23 additions & 13 deletions src/NexusMods.EventSourcing/PooledMemoryBufferWriter.cs
Original file line number Diff line number Diff line change
@@ -1,54 +1,64 @@
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using Reloaded.Memory.Extensions;

namespace NexusMods.EventSourcing;

public class PooledMemoryBufferWriter : IBufferWriter<byte>
public sealed class PooledMemoryBufferWriter : IBufferWriter<byte>
{
private IMemoryOwner<byte> _data;
private IMemoryOwner<byte> _owner;
private Memory<byte> _data;
private int _idx;
private int _size;

public PooledMemoryBufferWriter(int initialCapacity = 1024)
{
_data = MemoryPool<byte>.Shared.Rent(initialCapacity);
_owner = MemoryPool<byte>.Shared.Rent(initialCapacity);
_data = _owner.Memory;
_idx = 0;
_size = initialCapacity;
}

public void Reset()
{
_idx = 0;
}

public ReadOnlySpan<byte> GetWrittenSpan() => _data.Memory[.._idx].Span;
public ReadOnlySpan<byte> GetWrittenSpan() => _data.Span.SliceFast(0, _idx);

private void Expand()
{
var newSize = _data.Memory.Length * 2;
var newSize = _data.Length * 2;
var newData = MemoryPool<byte>.Shared.Rent(newSize);
_data.Memory.CopyTo(newData.Memory);
_data.Dispose();
_data = newData;
_data.CopyTo(newData.Memory);
_owner.Dispose();
_owner = newData;
_data = newData.Memory;
_size = newSize;
}


[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Advance(int count)
{
if (_idx + count > _data.Memory.Length)
if (_idx + count > _size)
Expand();
_idx += count;
}

public Memory<byte> GetMemory(int sizeHint = 0)
{
if (_idx + sizeHint > _data.Memory.Length)
if (_idx + sizeHint > _size)
Expand();
return _data.Memory[_idx..];
return _data[_idx..];
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<byte> GetSpan(int sizeHint = 0)
{
if (_idx + sizeHint > _data.Memory.Length)
if (_idx + sizeHint > _size)
Expand();
return _data.Memory.Span[_idx..];
return _data.Span.SliceFast(_idx);
}
}
4 changes: 4 additions & 0 deletions src/NexusMods.EventSourcing/Serialization/EventSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -308,12 +308,14 @@ private static void SortParams(MemberDefinition[] paramDefinitions, out bool isF
isFixedSize = unfixedParams.Count == 0;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Span<byte> SliceFastStart(ReadOnlySpan<byte> data, int start)
{
return MemoryMarshal.CreateSpan(ref Unsafe.Add(ref MemoryMarshal.GetReference(data), start),
data.Length - start);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Span<byte> SliceFastStartLength(Span<byte> data, int start, int length)
{
return MemoryMarshal.CreateSpan(ref Unsafe.Add(ref MemoryMarshal.GetReference(data), start), length);
Expand All @@ -322,11 +324,13 @@ internal static Span<byte> SliceFastStartLength(Span<byte> data, int start, int
private MethodInfo _sliceFastStartLengthMethodInfo =
typeof(BinaryEventSerializer).GetMethod(nameof(SliceFastStartLength), BindingFlags.Static | BindingFlags.NonPublic)!;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ReadOnlySpan<byte> ReadOnlySliceFastStartLength(ReadOnlySpan<byte> data, int start, int length)
{
return MemoryMarshal.CreateSpan(ref Unsafe.Add(ref MemoryMarshal.GetReference(data), start), length);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ReadOnlySpan<byte> ReadOnlySliceFastStart(ReadOnlySpan<byte> data, int start)
{
return MemoryMarshal.CreateSpan(ref Unsafe.Add(ref MemoryMarshal.GetReference(data), start), data.Length - start);
Expand Down
Loading

0 comments on commit 09c492c

Please sign in to comment.