diff --git a/src/benchmark/Akka.Benchmarks/Dispatch/DispatcherBenchmarks.cs b/src/benchmark/Akka.Benchmarks/Dispatch/DispatcherBenchmarks.cs new file mode 100644 index 00000000000..69b43364178 --- /dev/null +++ b/src/benchmark/Akka.Benchmarks/Dispatch/DispatcherBenchmarks.cs @@ -0,0 +1,121 @@ +// //----------------------------------------------------------------------- +// // +// // Copyright (C) 2009-2022 Lightbend Inc. +// // Copyright (C) 2013-2022 .NET Foundation +// // +// //----------------------------------------------------------------------- + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Akka.Actor; +using Akka.Benchmarks.Configurations; +using Akka.Configuration; +using Akka.Dispatch; +using BenchmarkDotNet.Attributes; +using IRunnable = Akka.Dispatch.IRunnable; + +namespace Akka.Benchmarks.Dispatch +{ + /// + /// Used to test the performance of various dispatchers + /// + [Config(typeof(MicroBenchmarkConfig))] + public class DispatcherBenchmarks + { + private ActorSystem _sys; + private DefaultDispatcherPrerequisites _prereqs; + + private MessageDispatcher _dispatcher; + + [Params(1_000_000)] // higher values will cause the CallingThreadDispatcher to stack overflow + public int TaskCount { get; set; } + + [ParamsSource(nameof(AllConfigurators))] + public DispatcherConfig Configurator { get; set; } + + public class DispatcherConfig + { + public DispatcherConfig(Config config, string name) + { + Config = config; + Name = name; + } + + public Config Config { get; } + + public string Name { get; } + + public override string ToString() + { + return Name; + } + } + + private static readonly Config DefaultConfig = Akka.Remote.Configuration.RemoteConfigFactory.Default() + .WithFallback(Akka.Configuration.ConfigurationFactory.Default()); + + public IEnumerable AllConfigurators() + { + yield return new DispatcherConfig(DefaultConfig.GetConfig("akka.actor.default-dispatcher"), "DefaultThreadPool"); + yield return new DispatcherConfig(DefaultConfig.GetConfig("akka.actor.internal-dispatcher"), "ForkJoin(sys)"); + yield return new DispatcherConfig(DefaultConfig.GetConfig("akka.remote.default-remote-dispatcher"), "ForkJoin(remote)"); + yield return new DispatcherConfig(@" executor = channel-executor + throughput=30", "ChannelD"); + yield return new DispatcherConfig(@" executor = task-executor + throughput=30", "TaskD"); + } + + private TaskCompletionSource _tcs; + + public sealed class RunnableTarget : IRunnable + { + private readonly TaskCompletionSource _tcs; + private readonly int _target; + private int _counter = 0; + + public RunnableTarget(TaskCompletionSource tcs, int target) + { + _tcs = tcs; + _target = target; + } + + public void Run() + { + if (Interlocked.Increment(ref _counter) >= _target) + { + _tcs.TrySetResult(_counter); + } + } + } + + private RunnableTarget _runnable; + + + [GlobalSetup] + public void Setup() + { + _sys = ActorSystem.Create("Bench"); + _prereqs = new DefaultDispatcherPrerequisites(_sys.EventStream, _sys.Scheduler, _sys.Settings, + _sys.Mailboxes); + var configurator = new DispatcherConfigurator(Configurator.Config, _prereqs); + _dispatcher = configurator.Dispatcher(); + _tcs = new TaskCompletionSource(); + _runnable = new RunnableTarget(_tcs, TaskCount); + } + + [GlobalCleanup] + public void CleanUp() + { + _sys.Terminate().Wait(); + } + + [Benchmark] + public async Task RunDispatcher() + { + for (var i = 0; i < TaskCount; i++) + _dispatcher.Schedule(_runnable); + await _tcs.Task; + } + } +} \ No newline at end of file diff --git a/src/benchmark/Akka.Benchmarks/Dispatch/MailboxThroughputBenchmarks.cs b/src/benchmark/Akka.Benchmarks/Dispatch/MailboxThroughputBenchmarks.cs index e9a118d622e..06aa8b7b955 100644 --- a/src/benchmark/Akka.Benchmarks/Dispatch/MailboxThroughputBenchmarks.cs +++ b/src/benchmark/Akka.Benchmarks/Dispatch/MailboxThroughputBenchmarks.cs @@ -69,6 +69,12 @@ public void Setup() _msg = new Envelope("hit", ActorRefs.NoSender); } + [GlobalCleanup] + public void CleanUp() + { + _system.Terminate().Wait(); + } + [IterationSetup] public void IterationSetup() {