Skip to content

Commit

Permalink
Added benchmarks (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
MattiasJakobsson authored Jun 7, 2024
1 parent ae93a37 commit 0d59f13
Show file tree
Hide file tree
Showing 34 changed files with 640 additions and 204 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ _site/
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# Benchmark Results
BenchmarkDotNet.Artifacts/

# NUNIT
*.VisualState.xml
TestResult.xml
Expand Down
17 changes: 17 additions & 0 deletions Akka.Persistence.EventStore.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Persistence.EventStore
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Persistence.EventStore.Hosting.Tests", "src\Akka.Persistence.EventStore.Hosting.Tests\Akka.Persistence.EventStore.Hosting.Tests.csproj", "{8D28138D-C51A-491A-B5EA-028D725B6442}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{6DCB3F60-66B1-44BE-AA32-C7CA4B11563D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Persistence.EventStore.Benchmarks", "src\Akka.Persistence.EventStore.Benchmarks\Akka.Persistence.EventStore.Benchmarks.csproj", "{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -97,6 +101,18 @@ Global
{8D28138D-C51A-491A-B5EA-028D725B6442}.Release|x64.Build.0 = Release|Any CPU
{8D28138D-C51A-491A-B5EA-028D725B6442}.Release|x86.ActiveCfg = Release|Any CPU
{8D28138D-C51A-491A-B5EA-028D725B6442}.Release|x86.Build.0 = Release|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Debug|x64.ActiveCfg = Debug|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Debug|x64.Build.0 = Debug|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Debug|x86.ActiveCfg = Debug|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Debug|x86.Build.0 = Debug|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Release|Any CPU.Build.0 = Release|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Release|x64.ActiveCfg = Release|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Release|x64.Build.0 = Release|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Release|x86.ActiveCfg = Release|Any CPU
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -108,5 +124,6 @@ Global
{96349315-C6BE-4888-B81A-9A46EF7CE685} = {F4AC94E7-D5F3-4B85-9810-A8BF02441883}
{DF2C9C02-9F0D-4FC8-8F72-234FD68FC918} = {F4AC94E7-D5F3-4B85-9810-A8BF02441883}
{6017AE31-4718-413B-983E-EAF9D4B465C9} = {DF2C9C02-9F0D-4FC8-8F72-234FD68FC918}
{EF1D827E-2B2B-4BA0-8733-D54CACDEE69F} = {6DCB3F60-66B1-44BE-AA32-C7CA4B11563D}
EndGlobalSection
EndGlobal
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
</PackageVersion>
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
<PackageVersion Include="Docker.DotNet" Version="3.125.15" />
<PackageVersion Include="BenchmarkDotNet" Version="0.13.12" />
</ItemGroup>
<ItemGroup>
<GlobalPackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="all" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Akka.Persistence.EventStore.Tests\Akka.Persistence.EventStore.Tests.csproj" />
<ProjectReference Include="..\Akka.Persistence.EventStore\Akka.Persistence.EventStore.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" />
<PackageReference Include="FluentAssertions" />
</ItemGroup>

<ItemGroup>
<None Update="benchmark.conf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
15 changes: 15 additions & 0 deletions src/Akka.Persistence.EventStore.Benchmarks/Const.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Akka.Persistence.EventStore.Benchmarks;

internal static class Const
{
public const int TotalMessages = 3000000;
public const int TagLowerBound = 2 * (TotalMessages / 3);
public const string Tag10 = "Tag1";
public const string Tag100 = "Tag2";
public const string Tag1000 = "Tag3";
public const string Tag10000 = "Tag4";
public const int Tag10UpperBound = TagLowerBound + 10;
public const int Tag100UpperBound = TagLowerBound + 100;
public const int Tag1000UpperBound = TagLowerBound + 1000;
public const int Tag10000UpperBound = TagLowerBound + 10000;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Akka.Actor;
using Akka.Configuration;
using Akka.Persistence.EventStore.Tests;
using FluentAssertions.Extensions;

namespace Akka.Persistence.EventStore.Benchmarks;

public static class EventStoreBenchmarkFixture
{
private static EventStoreContainer? _eventStoreContainer;

public static async Task<ActorSystem> CreateActorSystem(string name, Config? extraConfig = null)
{
var config = ConfigurationFactory.ParseString(await File.ReadAllTextAsync("benchmark.conf"))
.WithFallback(extraConfig ?? "")
.WithFallback(Persistence.DefaultConfig())
.WithFallback(EventStorePersistence.DefaultConfiguration);

return ActorSystem.Create(name, config);
}

public static async Task Initialize()
{
_eventStoreContainer = new EventStoreContainer();
await _eventStoreContainer.InitializeAsync();

await File.WriteAllTextAsync(
"benchmark.conf",
$$"""
akka.persistence.journal {
plugin = akka.persistence.journal.eventstore
eventstore {
connection-string = "{{_eventStoreContainer.ConnectionString}}"
event-adapters {
event-tagger = "{{typeof(EventTagger).AssemblyQualifiedName}}"
}
event-adapter-bindings {
"System.Int32" = event-tagger
}
}
}
akka.persistence.query.journal.eventstore {
write-plugin = akka.persistence.journal.eventstore
}
""");

var sys = await CreateActorSystem("Initializer", """
akka.persistence.journal {
eventstore {
auto-initialize = true
}
}
""");

var initializer = sys.ActorOf(Props.Create(() => new InitializeDbActor()), "INITIALIZER");

await initializer.Ask<InitializeDbActor.Initialized>(
InitializeDbActor.Initialize.Instance,
20.Minutes());
}

public static async Task Dispose()
{
if (_eventStoreContainer is not null)
await _eventStoreContainer.DisposeAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using Akka.Actor;
using Akka.Persistence.EventStore.Query;
using Akka.Persistence.Query;
using Akka.Streams;
using BenchmarkDotNet.Attributes;
using FluentAssertions;

namespace Akka.Persistence.EventStore.Benchmarks;

[Config(typeof(MicroBenchmarkConfig))]
public class EventStoreTagBenchmark
{
private IMaterializer? _materializer;
private IReadJournal? _readJournal;

private ActorSystem? _sys;

[GlobalSetup]
public async Task Setup()
{
_sys = await EventStoreBenchmarkFixture.CreateActorSystem("system");
_materializer = _sys.Materializer();
_readJournal = _sys.ReadJournalFor<EventStoreReadJournal>("akka.persistence.query.journal.eventstore");
}

[GlobalCleanup]
public async Task Cleanup()
{
if (_sys is not null)
await _sys.Terminate();
}

[Benchmark]
public async Task QueryByTag10()
{
var events = new List<EventEnvelope>();
var source = ((ICurrentEventsByTagQuery)_readJournal!).CurrentEventsByTag(Const.Tag10, NoOffset.Instance);
await source.RunForeach(
msg => { events.Add(msg); },
_materializer);
events.Select(e => e.SequenceNr).Should().BeEquivalentTo(Enumerable.Range(2000001, 10));
}

[Benchmark]
public async Task QueryByTag100()
{
var events = new List<EventEnvelope>();
var source = ((ICurrentEventsByTagQuery)_readJournal!).CurrentEventsByTag(Const.Tag100, NoOffset.Instance);
await source.RunForeach(
msg => { events.Add(msg); },
_materializer);
events.Select(e => e.SequenceNr).Should().BeEquivalentTo(Enumerable.Range(2000001, 100));
}

[Benchmark]
public async Task QueryByTag1000()
{
var events = new List<EventEnvelope>();
var source = ((ICurrentEventsByTagQuery)_readJournal!).CurrentEventsByTag(Const.Tag1000, NoOffset.Instance);
await source.RunForeach(
msg => { events.Add(msg); },
_materializer);
events.Select(e => e.SequenceNr).Should().BeEquivalentTo(Enumerable.Range(2000001, 1000));
}

[Benchmark]
public async Task QueryByTag10000()
{
var events = new List<EventEnvelope>();
var source = ((ICurrentEventsByTagQuery)_readJournal!).CurrentEventsByTag(Const.Tag10000, NoOffset.Instance);
await source.RunForeach(
msg => { events.Add(msg); },
_materializer);
events.Select(e => e.SequenceNr).Should().BeEquivalentTo(Enumerable.Range(2000001, 10000));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using Akka.Actor;
using BenchmarkDotNet.Attributes;

namespace Akka.Persistence.EventStore.Benchmarks;

[Config(typeof(MicroBenchmarkConfig))]
public class EventStoreWriteBenchmark
{
private ActorSystem? _sys;

[GlobalSetup]
public async Task Setup()
{
_sys = await EventStoreBenchmarkFixture.CreateActorSystem("system");
}

[GlobalCleanup]
public async Task Cleanup()
{
if (_sys is not null)
await _sys.Terminate();
}

[Benchmark]
public async Task Write10Events()
{
var writeEventsActor = _sys!.ActorOf(Props.Create(() => new WriteEventsActor(Guid.NewGuid().ToString())));

for (var i = 0; i < 10; i++)
{
await writeEventsActor.Ask<WriteEventsActor.Responses.WriteEventsResponse>(
new WriteEventsActor.Commands.WriteEvents(1));
}
}

[Benchmark]
public async Task Write100Events()
{
var writeEventsActor = _sys!.ActorOf(Props.Create(() => new WriteEventsActor(Guid.NewGuid().ToString())));

for (var i = 0; i < 100; i++)
{
await writeEventsActor.Ask<WriteEventsActor.Responses.WriteEventsResponse>(
new WriteEventsActor.Commands.WriteEvents(1));
}
}

[Benchmark]
public async Task Write10EventsBatched()
{
var writeEventsActor = _sys!.ActorOf(Props.Create(() => new WriteEventsActor(Guid.NewGuid().ToString())));

await writeEventsActor.Ask<WriteEventsActor.Responses.WriteEventsResponse>(
new WriteEventsActor.Commands.WriteEvents(10));
}

[Benchmark]
public async Task Write100EventsBatched()
{
var writeEventsActor = _sys!.ActorOf(Props.Create(() => new WriteEventsActor(Guid.NewGuid().ToString())));

await writeEventsActor.Ask<WriteEventsActor.Responses.WriteEventsResponse>(
new WriteEventsActor.Commands.WriteEvents(100));
}

private class WriteEventsActor : ReceivePersistentActor
{
public static class Commands
{
public record WriteEvents(int NumberOfEvents);
}

public static class Responses
{
public record WriteEventsResponse;
}

public override string PersistenceId { get; }

public WriteEventsActor(string id)
{
PersistenceId = id;

Command<Commands.WriteEvents>(cmd =>
{
var events = Enumerable.Range(1, cmd.NumberOfEvents).Select(_ => Guid.NewGuid());

PersistAll(events, _ => { });

DeferAsync("done", _ =>
{
Sender.Tell(new Responses.WriteEventsResponse());
});
});
}
}
}
24 changes: 24 additions & 0 deletions src/Akka.Persistence.EventStore.Benchmarks/EventTagger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Akka.Persistence.Journal;

namespace Akka.Persistence.EventStore.Benchmarks;

public sealed class EventTagger : IWriteEventAdapter
{
public string Manifest(object evt) => string.Empty;

public object ToJournal(object evt)
{
if (evt is not int i)
return evt;

return i switch
{
<= Const.TagLowerBound => evt,
<= Const.Tag10UpperBound => new Tagged(evt, new[] { Const.Tag10, Const.Tag100, Const.Tag1000, Const.Tag10000 }),
<= Const.Tag100UpperBound => new Tagged(evt, new[] { Const.Tag100, Const.Tag1000, Const.Tag10000 }),
<= Const.Tag1000UpperBound => new Tagged(evt, new[] { Const.Tag1000, Const.Tag10000 }),
<= Const.Tag10000UpperBound => new Tagged(evt, new[] { Const.Tag10000 }),
_ => evt,
};
}
}
Loading

0 comments on commit 0d59f13

Please sign in to comment.