From 611d76db7a139386836ab0233617670f8e53856e Mon Sep 17 00:00:00 2001 From: SH42913 Date: Mon, 26 Jun 2023 07:45:45 +0400 Subject: [PATCH] Added benchmark for Morpeh ECS framework --- README.md | 1 + source/Ecs.CSharp.Benchmark/Categories.cs | 1 + .../Context/MorpehBaseContext.cs | 35 +++++ .../CreateEntityWithOneComponent/Morpeh.cs | 40 ++++++ .../CreateEntityWithThreeComponents/Morpeh.cs | 43 ++++++ .../CreateEntityWithTwoComponents/Morpeh.cs | 46 +++++++ .../Ecs.CSharp.Benchmark.csproj | 2 + .../SystemWithOneComponent/Morpeh.cs | 95 ++++++++++++++ .../SystemWithThreeComponents/Morpeh.cs | 119 +++++++++++++++++ .../SystemWithTwoComponents/Morpeh.cs | 110 ++++++++++++++++ .../Morpeh.cs | 122 ++++++++++++++++++ 11 files changed, 614 insertions(+) create mode 100644 source/Ecs.CSharp.Benchmark/Context/MorpehBaseContext.cs create mode 100644 source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/Morpeh.cs create mode 100644 source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/Morpeh.cs create mode 100644 source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/Morpeh.cs create mode 100644 source/Ecs.CSharp.Benchmark/SystemWithOneComponent/Morpeh.cs create mode 100644 source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/Morpeh.cs create mode 100644 source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/Morpeh.cs create mode 100644 source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/Morpeh.cs diff --git a/README.md b/README.md index dc8665c..84b6023 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Tested frameworks: - [MonoGame.Extended](https://github.com/craftworkgames/MonoGame.Extended) - [RelEcs](https://github.com/Byteron/RelEcs) - [Svelto.ECS](https://github.com/sebas77/Svelto.ECS) +- [Morpeh](https://github.com/scellecs/morpeh) ## [CreateEntityWithOneComponent](results/Ecs.CSharp.Benchmark.CreateEntityWithOneComponent-report-github.md) Create entities with one component. diff --git a/source/Ecs.CSharp.Benchmark/Categories.cs b/source/Ecs.CSharp.Benchmark/Categories.cs index 1f3e0c8..823a41d 100644 --- a/source/Ecs.CSharp.Benchmark/Categories.cs +++ b/source/Ecs.CSharp.Benchmark/Categories.cs @@ -11,6 +11,7 @@ internal static class Categories public const string MonoGameExtended = "MonoGame.Extended"; public const string RelEcs = "RelEcs"; public const string SveltoECS = "Svelto.ECS"; + public const string Morpeh = "Morpeh"; public const string CreateEntity = "CreateEntity"; public const string System = "System"; diff --git a/source/Ecs.CSharp.Benchmark/Context/MorpehBaseContext.cs b/source/Ecs.CSharp.Benchmark/Context/MorpehBaseContext.cs new file mode 100644 index 0000000..e72e1cf --- /dev/null +++ b/source/Ecs.CSharp.Benchmark/Context/MorpehBaseContext.cs @@ -0,0 +1,35 @@ +using System; +using Scellecs.Morpeh; + +namespace Ecs.CSharp.Benchmark.Context +{ + internal class MorpehBaseContext : IDisposable + { + public struct Component1 : IComponent + { + public int Value; + } + + public struct Component2 : IComponent + { + public int Value; + } + + public struct Component3 : IComponent + { + public int Value; + } + + public World World { get; } + + protected MorpehBaseContext() + { + World = World.Create(); + } + + public virtual void Dispose() + { + World.Dispose(); + } + } +} diff --git a/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/Morpeh.cs b/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/Morpeh.cs new file mode 100644 index 0000000..0cc6bba --- /dev/null +++ b/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/Morpeh.cs @@ -0,0 +1,40 @@ +using BenchmarkDotNet.Attributes; +using Ecs.CSharp.Benchmark.Context; +using Scellecs.Morpeh; + +namespace Ecs.CSharp.Benchmark +{ + public partial class CreateEntityWithOneComponent + { + [Context] + private readonly MorpehBaseContext _context; + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Direct() + { + World world = _context.World; + for (int i = 0; i < EntityCount; ++i) + { + world.CreateEntity().AddComponent(); + } + + world.Commit(); + } + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Stash() + { + World world = _context.World; + Stash stash1 = world.GetStash(); + for (int i = 0; i < EntityCount; ++i) + { + Entity entity = world.CreateEntity(); + stash1.Add(entity); + } + + world.Commit(); + } + } +} diff --git a/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/Morpeh.cs b/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/Morpeh.cs new file mode 100644 index 0000000..663d40a --- /dev/null +++ b/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/Morpeh.cs @@ -0,0 +1,43 @@ +using BenchmarkDotNet.Attributes; +using Ecs.CSharp.Benchmark.Context; +using Scellecs.Morpeh; + +namespace Ecs.CSharp.Benchmark +{ + public partial class CreateEntityWithThreeComponents + { + [Context] + private readonly MorpehBaseContext _context; + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Direct() + { + World world = _context.World; + for (int i = 0; i < EntityCount; ++i) + { + world.CreateEntity().AddComponent(); + world.CreateEntity().AddComponent(); + } + + world.Commit(); + } + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Stash() + { + World world = _context.World; + Stash stash1 = world.GetStash(); + Stash stash2 = world.GetStash(); + for (int i = 0; i < EntityCount; ++i) + { + Entity entity = world.CreateEntity(); + stash1.Add(entity); + stash2.Add(entity); + } + + world.Commit(); + } + } +} diff --git a/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/Morpeh.cs b/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/Morpeh.cs new file mode 100644 index 0000000..c5722b1 --- /dev/null +++ b/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/Morpeh.cs @@ -0,0 +1,46 @@ +using BenchmarkDotNet.Attributes; +using Ecs.CSharp.Benchmark.Context; +using Scellecs.Morpeh; + +namespace Ecs.CSharp.Benchmark +{ + public partial class CreateEntityWithTwoComponents + { + [Context] + private readonly MorpehBaseContext _context; + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Direct() + { + World world = _context.World; + for (int i = 0; i < EntityCount; ++i) + { + world.CreateEntity().AddComponent(); + world.CreateEntity().AddComponent(); + world.CreateEntity().AddComponent(); + } + + world.Commit(); + } + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Stash() + { + World world = _context.World; + Stash stash1 = world.GetStash(); + Stash stash2 = world.GetStash(); + Stash stash3 = world.GetStash(); + for (int i = 0; i < EntityCount; ++i) + { + Entity entity = world.CreateEntity(); + stash1.Add(entity); + stash2.Add(entity); + stash3.Add(entity); + } + + world.Commit(); + } + } +} diff --git a/source/Ecs.CSharp.Benchmark/Ecs.CSharp.Benchmark.csproj b/source/Ecs.CSharp.Benchmark/Ecs.CSharp.Benchmark.csproj index b39969a..949b014 100644 --- a/source/Ecs.CSharp.Benchmark/Ecs.CSharp.Benchmark.csproj +++ b/source/Ecs.CSharp.Benchmark/Ecs.CSharp.Benchmark.csproj @@ -44,6 +44,8 @@ + + diff --git a/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/Morpeh.cs b/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/Morpeh.cs new file mode 100644 index 0000000..350fe26 --- /dev/null +++ b/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/Morpeh.cs @@ -0,0 +1,95 @@ +using System; +using BenchmarkDotNet.Attributes; +using Ecs.CSharp.Benchmark.Context; +using Scellecs.Morpeh; + +namespace Ecs.CSharp.Benchmark +{ + public partial class SystemWithOneComponent + { + private sealed class MorpehContext : MorpehBaseContext + { + private sealed class DirectSystem : ISystem + { + public World World { get; set; } + private Filter _filter; + + public void OnAwake() + { + _filter = World.Filter.With(); + } + + public void OnUpdate(float deltaTime) + { + foreach (Entity entity in _filter) + { + ++entity.GetComponent().Value; + } + } + + void IDisposable.Dispose() { } + } + + private sealed class StashSystem : ISystem + { + public World World { get; set; } + private Stash _stash1; + private Filter _filter; + + public void OnAwake() + { + _stash1 = World.GetStash(); + _filter = World.Filter.With(); + } + + public void OnUpdate(float deltaTime) + { + foreach (Entity entity in _filter) + { + ++_stash1.Get(entity).Value; + } + } + + public void Dispose() + { + _stash1.Dispose(); + } + } + + public ISystem MonoThreadDirectSystem { get; } + public ISystem MonoThreadStashSystem { get; } + + public MorpehContext(int entityCount, int entityPadding) + { + MonoThreadDirectSystem = new DirectSystem { World = World }; + MonoThreadDirectSystem.OnAwake(); + + MonoThreadStashSystem = new StashSystem { World = World }; + MonoThreadStashSystem.OnAwake(); + + for (int i = 0; i < entityCount; ++i) + { + for (int j = 0; j < entityPadding; ++j) + { + World.CreateEntity(); + } + + World.CreateEntity().AddComponent(); + } + + World.Commit(); + } + } + + [Context] + private readonly MorpehContext _context; + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Direct() => _context.MonoThreadDirectSystem.OnUpdate(0f); + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Stash() => _context.MonoThreadStashSystem.OnUpdate(0f); + } +} diff --git a/source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/Morpeh.cs b/source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/Morpeh.cs new file mode 100644 index 0000000..13c0df5 --- /dev/null +++ b/source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/Morpeh.cs @@ -0,0 +1,119 @@ +using System; +using BenchmarkDotNet.Attributes; +using Ecs.CSharp.Benchmark.Context; +using Scellecs.Morpeh; + +namespace Ecs.CSharp.Benchmark +{ + public partial class SystemWithThreeComponents + { + private sealed class MorpehContext : MorpehBaseContext + { + private sealed class DirectSystem : ISystem + { + public World World { get; set; } + private Filter _filter; + + public void OnAwake() + { + _filter = World.Filter.With().With().With(); + } + + public void OnUpdate(float deltaTime) + { + foreach (Entity entity in _filter) + { + entity.GetComponent().Value += entity.GetComponent().Value + + entity.GetComponent().Value; + } + } + + void IDisposable.Dispose() { } + } + + private sealed class StashSystem : ISystem + { + public World World { get; set; } + private Stash _stash1; + private Stash _stash2; + private Stash _stash3; + private Filter _filter; + + public void OnAwake() + { + _stash1 = World.GetStash(); + _stash2 = World.GetStash(); + _stash3 = World.GetStash(); + _filter = World.Filter.With().With().With(); + } + + public void OnUpdate(float deltaTime) + { + foreach (Entity entity in _filter) + { + _stash1.Get(entity).Value += _stash2.Get(entity).Value + _stash3.Get(entity).Value; + } + } + + public void Dispose() + { + _stash1.Dispose(); + _stash2.Dispose(); + _stash3.Dispose(); + } + } + + public ISystem MonoThreadDirectSystem { get; } + public ISystem MonoThreadStashSystem { get; } + + public MorpehContext(int entityCount, int entityPadding) + { + MonoThreadDirectSystem = new DirectSystem { World = World }; + MonoThreadDirectSystem.OnAwake(); + + MonoThreadStashSystem = new StashSystem { World = World }; + MonoThreadStashSystem.OnAwake(); + + for (int i = 0; i < entityCount; ++i) + { + for (int j = 0; j < entityPadding; ++j) + { + Entity padding = World.CreateEntity(); + switch (j % 3) + { + case 0: + padding.AddComponent(); + break; + + case 1: + padding.AddComponent(); + break; + + case 2: + padding.AddComponent(); + break; + } + } + + Entity entity = World.CreateEntity(); + entity.AddComponent(); + entity.SetComponent(new Component2 { Value = 1 }); + entity.SetComponent(new Component3 { Value = 1 }); + } + + World.Commit(); + } + } + + [Context] + private readonly MorpehContext _context; + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Direct() => _context.MonoThreadDirectSystem.OnUpdate(0f); + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Stash() => _context.MonoThreadStashSystem.OnUpdate(0f); + } +} diff --git a/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/Morpeh.cs b/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/Morpeh.cs new file mode 100644 index 0000000..7ae1b5e --- /dev/null +++ b/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/Morpeh.cs @@ -0,0 +1,110 @@ +using System; +using BenchmarkDotNet.Attributes; +using Ecs.CSharp.Benchmark.Context; +using Scellecs.Morpeh; + +namespace Ecs.CSharp.Benchmark +{ + public partial class SystemWithTwoComponents + { + private sealed class MorpehContext : MorpehBaseContext + { + private sealed class DirectSystem : ISystem + { + public World World { get; set; } + private Filter _filter; + + public void OnAwake() + { + _filter = World.Filter.With().With(); + } + + public void OnUpdate(float deltaTime) + { + foreach (Entity entity in _filter) + { + entity.GetComponent().Value += entity.GetComponent().Value; + } + } + + void IDisposable.Dispose() { } + } + + private sealed class StashSystem : ISystem + { + public World World { get; set; } + private Stash _stash1; + private Stash _stash2; + private Filter _filter; + + public void OnAwake() + { + _stash1 = World.GetStash(); + _stash2 = World.GetStash(); + _filter = World.Filter.With().With(); + } + + public void OnUpdate(float deltaTime) + { + foreach (Entity entity in _filter) + { + _stash1.Get(entity).Value += _stash2.Get(entity).Value; + } + } + + public void Dispose() + { + _stash1.Dispose(); + _stash2.Dispose(); + } + } + + public ISystem MonoThreadDirectSystem { get; } + public ISystem MonoThreadStashSystem { get; } + + public MorpehContext(int entityCount, int entityPadding) + { + MonoThreadDirectSystem = new DirectSystem { World = World }; + MonoThreadDirectSystem.OnAwake(); + + MonoThreadStashSystem = new StashSystem { World = World }; + MonoThreadStashSystem.OnAwake(); + + for (int i = 0; i < entityCount; ++i) + { + for (int j = 0; j < entityPadding; ++j) + { + Entity padding = World.CreateEntity(); + switch (j % 2) + { + case 0: + padding.AddComponent(); + break; + + case 1: + padding.AddComponent(); + break; + } + } + + Entity entity = World.CreateEntity(); + entity.AddComponent(); + entity.SetComponent(new Component2 { Value = 1 }); + } + + World.Commit(); + } + } + + [Context] + private readonly MorpehContext _context; + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Direct() => _context.MonoThreadDirectSystem.OnUpdate(0f); + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Stash() => _context.MonoThreadStashSystem.OnUpdate(0f); + } +} diff --git a/source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/Morpeh.cs b/source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/Morpeh.cs new file mode 100644 index 0000000..95f082c --- /dev/null +++ b/source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/Morpeh.cs @@ -0,0 +1,122 @@ +using System; +using BenchmarkDotNet.Attributes; +using Ecs.CSharp.Benchmark.Context; +using Scellecs.Morpeh; + +namespace Ecs.CSharp.Benchmark +{ + public partial class SystemWithTwoComponentsMultipleComposition + { + private sealed class MorpehContext : MorpehBaseContext + { + private record struct Padding1() : IComponent; + + private record struct Padding2() : IComponent; + + private record struct Padding3() : IComponent; + + private record struct Padding4() : IComponent; + + private sealed class DirectSystem : ISystem + { + public World World { get; set; } + private Filter _filter; + + public void OnAwake() + { + _filter = World.Filter.With().With(); + } + + public void OnUpdate(float deltaTime) + { + foreach (Entity entity in _filter) + { + entity.GetComponent().Value += entity.GetComponent().Value; + } + } + + void IDisposable.Dispose() { } + } + + private sealed class StashSystem : ISystem + { + public World World { get; set; } + private Stash _stash1; + private Stash _stash2; + private Filter _filter; + + public void OnAwake() + { + _stash1 = World.GetStash(); + _stash2 = World.GetStash(); + _filter = World.Filter.With().With(); + } + + public void OnUpdate(float deltaTime) + { + foreach (Entity entity in _filter) + { + _stash1.Get(entity).Value += _stash2.Get(entity).Value; + } + } + + public void Dispose() + { + _stash1.Dispose(); + _stash2.Dispose(); + } + } + + public ISystem MonoThreadDirectSystem { get; } + public ISystem MonoThreadStashSystem { get; } + + public MorpehContext(int entityCount) + { + MonoThreadDirectSystem = new DirectSystem { World = World }; + MonoThreadDirectSystem.OnAwake(); + + MonoThreadStashSystem = new StashSystem { World = World }; + MonoThreadStashSystem.OnAwake(); + + for (int i = 0; i < entityCount; ++i) + { + Entity entity = World.CreateEntity(); + entity.AddComponent(); + entity.SetComponent(new Component2 { Value = 1 }); + + switch (i % 4) + { + case 0: + entity.AddComponent(); + break; + + case 1: + entity.AddComponent(); + break; + + case 2: + entity.AddComponent(); + break; + + case 3: + entity.AddComponent(); + break; + } + } + + World.Commit(); + } + } + + [Context] + private readonly MorpehContext _context; + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Direct() => _context.MonoThreadDirectSystem.OnUpdate(0f); + + [BenchmarkCategory(Categories.Morpeh)] + [Benchmark] + public void Morpeh_Stash() => _context.MonoThreadStashSystem.OnUpdate(0f); + } +}