diff --git a/src/benchmark/Akka.Benchmarks/Actor/FsmBenchmarks.cs b/src/benchmark/Akka.Benchmarks/Actor/FsmBenchmarks.cs new file mode 100644 index 00000000000..fe61c667618 --- /dev/null +++ b/src/benchmark/Akka.Benchmarks/Actor/FsmBenchmarks.cs @@ -0,0 +1,162 @@ +// //----------------------------------------------------------------------- +// // +// // Copyright (C) 2009-2022 Lightbend Inc. +// // Copyright (C) 2013-2022 .NET Foundation +// // +// //----------------------------------------------------------------------- + +using System.Threading.Tasks; +using Akka.Actor; +using Akka.Benchmarks.Configurations; +using BenchmarkDotNet.Attributes; + +namespace Akka.Benchmarks.Actor +{ + [Config(typeof(MicroBenchmarkConfig))] + public class FsmBenchmarks + { + #region Classes + + public enum States + { + Initial, + Running + } + + public sealed class FsmData + { + public FsmData(string d) + { + D = d; + } + + public string D { get; } + } + + public class BenchmarkFsmActor : FSM + { + public BenchmarkFsmActor(string init) + { + StartWith(States.Initial, new FsmData(init)); + + When(States.Initial, @e => + { + switch (e.FsmEvent) + { + case string str1 when e.StateData.D.Equals("transition"): + Sender.Tell(str1); + return GoTo(States.Running); + case string str2: + Sender.Tell(str2); + return Stay().Using(new FsmData(str2)); + default: + Sender.Tell(e.FsmEvent); + return Stay(); + } + }); + + When(States.Running, @e => + { + switch (e.FsmEvent) + { + case string str1 when e.StateData.D.Equals("transition"): + Sender.Tell(str1); + return GoTo(States.Initial); + case string str2: + Sender.Tell(str2); + return Stay().Using(new FsmData(str2)); + default: + Sender.Tell(e.FsmEvent); + return Stay(); + } + }); + } + } + + public class UntypedActorBaseline : UntypedActor + { + private FsmData _data; + + public UntypedActorBaseline(string d) + { + _data = new FsmData(d); + } + + protected override void OnReceive(object message) + { + switch (message) + { + case string str1 when _data.D.Equals("transition"): + Sender.Tell(str1); + break; + case string str2: + Sender.Tell(str2); + _data = new FsmData(str2); + break; + default: + Sender.Tell(message); + break; + } + } + } + + #endregion + + private ActorSystem _sys; + private IActorRef _fsmActor; + private IActorRef _untypedActor; + + [Params(1_000_000)] + public int MsgCount { get; set; } + + [GlobalSetup] + public void Setup() + { + _sys = ActorSystem.Create("Bench", @"akka.log-dead-letters = off"); + _fsmActor = _sys.ActorOf(Props.Create(() => new BenchmarkFsmActor("start"))); + _untypedActor = _sys.ActorOf(Props.Create(() => new UntypedActorBaseline("start"))); + } + + [GlobalCleanup] + public void CleanUp() + { + _sys.Terminate().Wait(); + } + + [Benchmark] + public async Task BenchmarkFsm() + { + for (var i = 0; i < MsgCount; i++) + { + if (i % 4 == 0) + { + _fsmActor.Tell("transition"); + } + else + { + _fsmActor.Tell(i); + } + } + + await _fsmActor.Ask("stop"); + } + + [Benchmark(Baseline = true)] + public async Task BenchmarkUntyped() + { + for (var i = 0; i < MsgCount; i++) + { + if (i % 4 == 0) + { + _untypedActor.Tell("transition"); + } + else + { + _untypedActor.Tell(i); + } + } + + await _untypedActor.Ask("stop"); + } + } +} \ No newline at end of file