├── .gitignore
├── source
├── NuGet.config
├── Ecs.CSharp.Benchmark
│ ├── ContextAttribute.cs
│ ├── CreateEntityWithOneComponent
│ │ ├── HypEcs.cs
│ │ ├── RelEcs.cs
│ │ ├── TinyEcs.cs
│ │ ├── MonoGameExtended.cs
│ │ ├── LeopotamEcs.cs
│ │ ├── _CreateEntityWithOneComponent.cs
│ │ ├── DefaultEcs.cs
│ │ ├── Fennecs.cs
│ │ ├── FlecsNet.cs
│ │ ├── LeopotamEcsLite.cs
│ │ ├── FrifloEngineEcs.cs
│ │ ├── SveltoECS.cs
│ │ ├── Arch.cs
│ │ ├── Myriad.cs
│ │ ├── Frent.cs
│ │ └── Morpeh.cs
│ ├── Contexts
│ │ ├── FrentBaseContext.cs
│ │ ├── TinyEcsBaseContext.cs
│ │ ├── HypEcsBaseContext.cs
│ │ ├── DefaultEcsBaseContext.cs
│ │ ├── RelEcsBaseContext.cs
│ │ ├── LeopotamEcsBaseContext.cs
│ │ ├── LeopotamEcsLiteBaseContext.cs
│ │ ├── MorpehBaseContext.cs
│ │ ├── FennecsBaseContext.cs
│ │ ├── FlecsNetBaseContext.cs
│ │ ├── MonoGameExtendedBaseContext.cs
│ │ ├── SveltoECSBaseContext.cs
│ │ ├── MyriadBaseContext.cs
│ │ ├── ArchBaseContext.cs
│ │ └── FrifloEngineEcsContext.cs
│ ├── CreateEntityWithTwoComponents
│ │ ├── HypEcs.cs
│ │ ├── RelEcs.cs
│ │ ├── _CreateEntityWithTwoComponents.cs
│ │ ├── TinyEcs.cs
│ │ ├── Fennecs.cs
│ │ ├── DefaultEcs.cs
│ │ ├── LeopotamEcs.cs
│ │ ├── FlecsNet.cs
│ │ ├── MonoGameExtended.cs
│ │ ├── FrifloEngineEcs.cs
│ │ ├── SveltoECS.cs
│ │ ├── Arch.cs
│ │ ├── Myriad.cs
│ │ ├── LeopotamEcsLite.cs
│ │ ├── Frent.cs
│ │ └── Morpeh.cs
│ ├── CreateEntityWithThreeComponents
│ │ ├── _CreateEntityWithThreeComponents.cs
│ │ ├── HypEcs.cs
│ │ ├── RelEcs.cs
│ │ ├── TinyEcs.cs
│ │ ├── DefaultEcs.cs
│ │ ├── LeopotamEcs.cs
│ │ ├── Fennecs.cs
│ │ ├── FrifloEngineEcs.cs
│ │ ├── SveltoECS.cs
│ │ ├── FlecsNet.cs
│ │ ├── Arch.cs
│ │ ├── MonoGameExtended.cs
│ │ ├── Myriad.cs
│ │ ├── LeopotamEcsLite.cs
│ │ ├── Morpeh.cs
│ │ └── Frent.cs
│ ├── SystemWithTwoComponentsMultipleComposition
│ │ ├── _SystemWithTwoComponentsMultipleComposition.cs
│ │ ├── RelEcs.cs
│ │ ├── TinyEcs.cs
│ │ ├── FlecsNet.cs
│ │ ├── LeopotamEcs.cs
│ │ ├── Fennecs.cs
│ │ ├── Frent.cs
│ │ ├── DefaultEcs.cs
│ │ ├── SveltoECS.cs
│ │ ├── LeopotamEcsLite.cs
│ │ ├── HypEcs.cs
│ │ └── MonoGameExtended.cs
│ ├── SystemWithOneComponent
│ │ ├── _SystemWithOneComponent.cs
│ │ ├── TinyEcs.cs
│ │ ├── RelEcs.cs
│ │ ├── FlecsNet.cs
│ │ ├── LeopotamEcs.cs
│ │ ├── Fennecs.cs
│ │ ├── Arch.cs
│ │ ├── SveltoECS.cs
│ │ ├── LeopotamEcsLite.cs
│ │ ├── HypEcs.cs
│ │ ├── Frent.cs
│ │ ├── MonoGameExtended.cs
│ │ ├── FrifloEngineEcs.cs
│ │ └── Morpeh.cs
│ ├── SystemWithTwoComponents
│ │ ├── _SystemWithTwoComponents.cs
│ │ ├── TinyEcs.cs
│ │ ├── RelEcs.cs
│ │ ├── Arch.cs
│ │ ├── LeopotamEcs.cs
│ │ ├── FlecsNet.cs
│ │ ├── Fennecs.cs
│ │ ├── Frent.cs
│ │ ├── SveltoECS.cs
│ │ ├── DefaultEcs.cs
│ │ ├── LeopotamEcsLite.cs
│ │ ├── HypEcs.cs
│ │ ├── MonoGameExtended.cs
│ │ └── FrifloEngineEcs.cs
│ ├── SystemWithThreeComponents
│ │ ├── _SystemWithThreeComponents.cs
│ │ ├── Arch.cs
│ │ ├── RelEcs.cs
│ │ ├── TinyEcs.cs
│ │ ├── LeopotamEcs.cs
│ │ ├── FlecsNet.cs
│ │ ├── Frent.cs
│ │ ├── Fennecs.cs
│ │ ├── DefaultEcs.cs
│ │ ├── SveltoECS.cs
│ │ ├── HypEcs.cs
│ │ └── LeopotamEcsLite.cs
│ ├── Categories.cs
│ ├── BenchmarkOperations.cs
│ ├── Program.cs
│ └── Ecs.CSharp.Benchmark.csproj
└── Ecs.CSharp.Benchmark.sln
├── Benchmark.bat
├── .github
├── workflows
│ ├── PullRequest.yml
│ └── ContinuousIntegration.yml
└── FUNDING.yml
├── LICENSE.md
└── results
├── Ecs.CSharp.Benchmark.CreateEntityWithThreeComponents-report-github.md
├── Ecs.CSharp.Benchmark.CreateEntityWithTwoComponents-report-github.md
└── Ecs.CSharp.Benchmark.CreateEntityWithOneComponent-report-github.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /**/obj
2 | /**/bin
3 | /**/.vs
4 | /**/*.vspscc
5 | /**/*.user
6 | /**/*.snk
7 | /BenchmarkDotNet.Artifacts
8 | .idea/
9 |
--------------------------------------------------------------------------------
/source/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/ContextAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ecs.CSharp.Benchmark
4 | {
5 | [AttributeUsage(AttributeTargets.Field)]
6 | internal sealed class ContextAttribute : Attribute
7 | { }
8 | }
9 |
--------------------------------------------------------------------------------
/Benchmark.bat:
--------------------------------------------------------------------------------
1 | @ECHO off
2 |
3 | pushd %~dp0
4 |
5 | DEL /q /s BenchmarkDotNet.Artifacts
6 | dotnet clean source\Ecs.CSharp.Benchmark\Ecs.CSharp.Benchmark.csproj -c Release
7 |
8 | dotnet build source\Ecs.CSharp.Benchmark\Ecs.CSharp.Benchmark.csproj -c Release /p:CheckCacheMisses=true
9 | IF %ERRORLEVEL% GTR 0 GOTO :end
10 |
11 | dotnet run --project source\Ecs.CSharp.Benchmark\Ecs.CSharp.Benchmark.csproj -c Release --no-build --anyCategories DefaultEcs
12 |
13 | :end
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/HypEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 |
4 | namespace Ecs.CSharp.Benchmark
5 | {
6 | public partial class CreateEntityWithOneComponent
7 | {
8 | [Context] private readonly HypEcsBaseContext _hypEcs;
9 |
10 | [BenchmarkCategory(Categories.RelEcs)]
11 | [Benchmark]
12 | public void HypEcs()
13 | {
14 | for (int i = 0; i < EntityCount; ++i)
15 | {
16 | _hypEcs.World.Spawn().Add(new HypEcsBaseContext.Component1());
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/FrentBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Frent;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | internal class FrentBaseContext : IDisposable
7 | {
8 | public World World { get; } = new();
9 | public void Dispose() => World.Dispose();
10 |
11 | internal struct Component1
12 | {
13 | public int Value;
14 | }
15 |
16 | internal struct Component2
17 | {
18 | public int Value;
19 | }
20 |
21 | internal struct Component3
22 | {
23 | public int Value;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/RelEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 |
4 | namespace Ecs.CSharp.Benchmark
5 | {
6 | public partial class CreateEntityWithOneComponent
7 | {
8 | [Context]
9 | private readonly RelEcsBaseContext _relEcs;
10 |
11 | [BenchmarkCategory(Categories.RelEcs)]
12 | [Benchmark]
13 | public void RelEcs()
14 | {
15 | for (int i = 0; i < EntityCount; ++i)
16 | {
17 | _relEcs.World.Spawn().Add(new RelEcsBaseContext.Component1());
18 | }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.github/workflows/PullRequest.yml:
--------------------------------------------------------------------------------
1 | name: pull request
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - 'source/**'
7 |
8 | jobs:
9 | pull_request:
10 | runs-on: windows-latest
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@v2
14 |
15 | - name: Set up dotnet
16 | uses: actions/setup-dotnet@v1
17 | with:
18 | dotnet-version: '8.0.x'
19 |
20 | - name: Build
21 | run: dotnet build source\Ecs.CSharp.Benchmark\Ecs.CSharp.Benchmark.csproj -c Release /warnaserror
22 |
23 | - name: Run benchmark
24 | run: dotnet run --project source\Ecs.CSharp.Benchmark\Ecs.CSharp.Benchmark.csproj -c Release --filter * --job Dry
25 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: https://paypal.me/LaszloPaillat
13 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/TinyEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using DefaultEcs;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 | using Ecs.CSharp.Benchmark.Contexts.TinyEcs_Components;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class CreateEntityWithOneComponent
9 | {
10 | [Context]
11 | private readonly TinyEcsBaseContext _tinyEcs;
12 |
13 | [BenchmarkCategory(Categories.TinyEcs)]
14 | [Benchmark]
15 | public void TinyEcs()
16 | {
17 | for (int i = 0; i < EntityCount; ++i)
18 | {
19 | _tinyEcs.World.Entity().Set();
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/HypEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 |
4 | namespace Ecs.CSharp.Benchmark
5 | {
6 | public partial class CreateEntityWithTwoComponents
7 | {
8 | [Context] private readonly HypEcsBaseContext _hypEcs;
9 |
10 | [BenchmarkCategory(Categories.HypEcs)]
11 | [Benchmark]
12 | public void HypEcs()
13 | {
14 | for (int i = 0; i < EntityCount; ++i)
15 | {
16 | _hypEcs.World.Spawn()
17 | .Add(new HypEcsBaseContext.Component1())
18 | .Add(new HypEcsBaseContext.Component2());
19 | }
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/MonoGameExtended.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 |
4 | namespace Ecs.CSharp.Benchmark
5 | {
6 | public partial class CreateEntityWithOneComponent
7 | {
8 | [Context]
9 | private readonly MonoGameExtendedBaseContext _monoGameExtended;
10 |
11 | [BenchmarkCategory(Categories.MonoGameExtended)]
12 | [Benchmark]
13 | public void MonoGameExtended()
14 | {
15 | for (int i = 0; i < EntityCount; ++i)
16 | {
17 | _monoGameExtended.World.CreateEntity().Attach(new MonoGameExtendedBaseContext.Component1());
18 | }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/LeopotamEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.Ecs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithOneComponent
8 | {
9 | [Context]
10 | private readonly LeopotamEcsBaseContext _leopotamEcs;
11 |
12 | [BenchmarkCategory(Categories.LeopotamEcs)]
13 | [Benchmark]
14 | public void LeopotamEcs()
15 | {
16 | for (int i = 0; i < EntityCount; ++i)
17 | {
18 | _leopotamEcs.World.NewEntity()
19 | .Replace(new LeopotamEcsBaseContext.Component1());
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/_CreateEntityWithOneComponent.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 |
3 | namespace Ecs.CSharp.Benchmark
4 | {
5 | [BenchmarkCategory(Categories.CreateEntity)]
6 | [MemoryDiagnoser]
7 | #if CHECK_CACHE_MISSES
8 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)]
9 | #endif
10 | public partial class CreateEntityWithOneComponent
11 | {
12 | [Params(100000)]
13 | public int EntityCount { get; set; }
14 |
15 | [IterationSetup]
16 | public void Setup() => BenchmarkOperations.SetupContexts(this);
17 |
18 | [IterationCleanup]
19 | public void Cleanup() => BenchmarkOperations.CleanupContexts(this);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/RelEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 |
4 | namespace Ecs.CSharp.Benchmark
5 | {
6 | public partial class CreateEntityWithTwoComponents
7 | {
8 | [Context]
9 | private readonly RelEcsBaseContext _relEcs;
10 |
11 | [BenchmarkCategory(Categories.RelEcs)]
12 | [Benchmark]
13 | public void RelEcs()
14 | {
15 | for (int i = 0; i < EntityCount; ++i)
16 | {
17 | _relEcs.World.Spawn()
18 | .Add(new RelEcsBaseContext.Component1())
19 | .Add(new RelEcsBaseContext.Component2());
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/DefaultEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using DefaultEcs;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithOneComponent
8 | {
9 | [Context]
10 | private readonly DefaultEcsBaseContext _defaultEcs;
11 |
12 | [BenchmarkCategory(Categories.DefaultEcs)]
13 | [Benchmark]
14 | public void DefaultEcs()
15 | {
16 | for (int i = 0; i < EntityCount; ++i)
17 | {
18 | Entity entity = _defaultEcs.World.CreateEntity();
19 | entity.Set();
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/_CreateEntityWithTwoComponents.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 |
3 | namespace Ecs.CSharp.Benchmark
4 | {
5 | [BenchmarkCategory(Categories.CreateEntity)]
6 | [MemoryDiagnoser]
7 | #if CHECK_CACHE_MISSES
8 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)]
9 | #endif
10 | public partial class CreateEntityWithTwoComponents
11 | {
12 | [Params(100000)]
13 | public int EntityCount { get; set; }
14 |
15 | [IterationSetup]
16 | public void Setup() => BenchmarkOperations.SetupContexts(this);
17 |
18 | [IterationCleanup]
19 | public void Cleanup() => BenchmarkOperations.CleanupContexts(this);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/TinyEcsBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using TinyEcs;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | namespace TinyEcs_Components
7 | {
8 | public record struct Component1(int Value);
9 |
10 | public record struct Component2(int Value);
11 |
12 | public record struct Component3(int Value);
13 | }
14 |
15 | internal class TinyEcsBaseContext : IDisposable
16 | {
17 | public World World { get; }
18 |
19 | public TinyEcsBaseContext()
20 | {
21 | World = new World();
22 | }
23 |
24 | public virtual void Dispose()
25 | {
26 | World?.Dispose();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/_CreateEntityWithThreeComponents.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 |
3 | namespace Ecs.CSharp.Benchmark
4 | {
5 | [BenchmarkCategory(Categories.CreateEntity)]
6 | [MemoryDiagnoser]
7 | #if CHECK_CACHE_MISSES
8 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)]
9 | #endif
10 | public partial class CreateEntityWithThreeComponents
11 | {
12 | [Params(100000)]
13 | public int EntityCount { get; set; }
14 |
15 | [IterationSetup]
16 | public void Setup() => BenchmarkOperations.SetupContexts(this);
17 |
18 | [IterationCleanup]
19 | public void Cleanup() => BenchmarkOperations.CleanupContexts(this);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/Fennecs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.Fennecs_Components;
4 | using fennecs;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class CreateEntityWithOneComponent
9 | {
10 | [Context] private readonly FennecsBaseContext _fennecs;
11 |
12 | [BenchmarkCategory(Categories.Fennecs)]
13 | [Benchmark]
14 | public void Fennecs()
15 | {
16 | World world = _fennecs.World;
17 |
18 | for (int i = 0; i < EntityCount; ++i)
19 | {
20 | world.Spawn().Add();
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/_SystemWithTwoComponentsMultipleComposition.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 |
3 | namespace Ecs.CSharp.Benchmark
4 | {
5 | [BenchmarkCategory(Categories.System)]
6 | [MemoryDiagnoser]
7 | #if CHECK_CACHE_MISSES
8 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)]
9 | #endif
10 | public partial class SystemWithTwoComponentsMultipleComposition
11 | {
12 | [Params(100000)]
13 | public int EntityCount { get; set; }
14 |
15 | [GlobalSetup]
16 | public void Setup() => BenchmarkOperations.SetupContexts(this, EntityCount);
17 |
18 | [GlobalCleanup]
19 | public void Cleanup() => BenchmarkOperations.CleanupContexts(this);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/HypEcsBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using HypEcs;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | internal class HypEcsBaseContext : IDisposable
7 | {
8 | public struct Component1
9 | {
10 | public int Value;
11 | }
12 |
13 | public struct Component2
14 | {
15 | public int Value;
16 | }
17 |
18 | public struct Component3
19 | {
20 | public int Value;
21 | }
22 |
23 | public World World { get; }
24 |
25 | public HypEcsBaseContext()
26 | {
27 | World = new World();
28 | }
29 |
30 | public virtual void Dispose()
31 | {
32 | // World.Destroy();
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/TinyEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using DefaultEcs;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 | using Ecs.CSharp.Benchmark.Contexts.TinyEcs_Components;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class CreateEntityWithTwoComponents
9 | {
10 | [Context]
11 | private readonly TinyEcsBaseContext _tinyEcs;
12 |
13 | [BenchmarkCategory(Categories.TinyEcs)]
14 | [Benchmark]
15 | public void TinyEcs()
16 | {
17 | for (int i = 0; i < EntityCount; ++i)
18 | {
19 | _tinyEcs.World.Entity()
20 | .Set()
21 | .Set();
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/HypEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 |
4 | namespace Ecs.CSharp.Benchmark
5 | {
6 | public partial class CreateEntityWithThreeComponents
7 | {
8 | [Context] private readonly HypEcsBaseContext _hypEcs;
9 |
10 | [BenchmarkCategory(Categories.HypEcs)]
11 | [Benchmark]
12 | public void HypEcs()
13 | {
14 | for (int i = 0; i < EntityCount; ++i)
15 | {
16 | _hypEcs.World.Spawn()
17 | .Add(new HypEcsBaseContext.Component1())
18 | .Add(new HypEcsBaseContext.Component2())
19 | .Add(new HypEcsBaseContext.Component3());
20 | }
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/DefaultEcsBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DefaultEcs;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | internal class DefaultEcsBaseContext : IDisposable
7 | {
8 | public struct Component1
9 | {
10 | public int Value;
11 | }
12 |
13 | public struct Component2
14 | {
15 | public int Value;
16 | }
17 |
18 | public struct Component3
19 | {
20 | public int Value;
21 | }
22 |
23 | public World World { get; }
24 |
25 | public DefaultEcsBaseContext()
26 | {
27 | World = new World();
28 | }
29 |
30 | public virtual void Dispose()
31 | {
32 | World.Dispose();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/RelEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 |
4 | namespace Ecs.CSharp.Benchmark
5 | {
6 | public partial class CreateEntityWithThreeComponents
7 | {
8 | [Context]
9 | private readonly RelEcsBaseContext _relEcs;
10 |
11 | [BenchmarkCategory(Categories.RelEcs)]
12 | [Benchmark]
13 | public void RelEcs()
14 | {
15 | for (int i = 0; i < EntityCount; ++i)
16 | {
17 | _relEcs.World.Spawn()
18 | .Add(new RelEcsBaseContext.Component1())
19 | .Add(new RelEcsBaseContext.Component2())
20 | .Add(new RelEcsBaseContext.Component3());
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/RelEcsBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using RelEcs;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | internal class RelEcsBaseContext : IDisposable
7 | {
8 | public sealed class Component1
9 | {
10 | public int Value;
11 | }
12 |
13 | public sealed class Component2
14 | {
15 | public int Value;
16 | }
17 |
18 | public sealed class Component3
19 | {
20 | public int Value;
21 | }
22 |
23 | public World World { get; }
24 |
25 | public RelEcsBaseContext()
26 | {
27 | World = new World();
28 | }
29 |
30 | public virtual void Dispose()
31 | {
32 | // World.Destroy();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/Fennecs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.Fennecs_Components;
4 | using fennecs;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class CreateEntityWithTwoComponents
9 | {
10 | [Context] private readonly FennecsBaseContext _fennecs;
11 |
12 | [BenchmarkCategory(Categories.Fennecs)]
13 | [Benchmark]
14 | public void Fennecs()
15 | {
16 | World world = _fennecs.World;
17 |
18 | for (int i = 0; i < EntityCount; ++i)
19 | {
20 | world.Spawn().
21 | Add().Add();
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/LeopotamEcsBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Leopotam.Ecs;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | internal class LeopotamEcsBaseContext : IDisposable
7 | {
8 | public struct Component1
9 | {
10 | public int Value;
11 | }
12 |
13 | public struct Component2
14 | {
15 | public int Value;
16 | }
17 |
18 | public struct Component3
19 | {
20 | public int Value;
21 | }
22 |
23 | public EcsWorld World { get; }
24 |
25 | public LeopotamEcsBaseContext()
26 | {
27 | World = new EcsWorld();
28 | }
29 |
30 | public virtual void Dispose()
31 | {
32 | World.Destroy();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/DefaultEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using DefaultEcs;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithTwoComponents
8 | {
9 | [Context]
10 | private readonly DefaultEcsBaseContext _defaultEcs;
11 |
12 | [BenchmarkCategory(Categories.DefaultEcs)]
13 | [Benchmark]
14 | public void DefaultEcs()
15 | {
16 | for (int i = 0; i < EntityCount; ++i)
17 | {
18 | Entity entity = _defaultEcs.World.CreateEntity();
19 | entity.Set();
20 | entity.Set();
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/LeopotamEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.Ecs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithTwoComponents
8 | {
9 | [Context]
10 | private readonly LeopotamEcsBaseContext _leopotamEcs;
11 |
12 | [BenchmarkCategory(Categories.LeopotamEcs)]
13 | [Benchmark]
14 | public void LeopotamEcs()
15 | {
16 | for (int i = 0; i < EntityCount; ++i)
17 | {
18 | _leopotamEcs.World.NewEntity()
19 | .Replace(new LeopotamEcsBaseContext.Component1())
20 | .Replace(new LeopotamEcsBaseContext.Component2());
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/_SystemWithOneComponent.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 |
3 | namespace Ecs.CSharp.Benchmark
4 | {
5 | [BenchmarkCategory(Categories.System)]
6 | [MemoryDiagnoser]
7 | #if CHECK_CACHE_MISSES
8 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)]
9 | #endif
10 | public partial class SystemWithOneComponent
11 | {
12 | [Params(100000)]
13 | public int EntityCount { get; set; }
14 |
15 | [Params(0, 10)]
16 | public int EntityPadding { get; set; }
17 |
18 | [GlobalSetup]
19 | public void Setup() => BenchmarkOperations.SetupContexts(this, EntityCount, EntityPadding);
20 |
21 | [GlobalCleanup]
22 | public void Cleanup() => BenchmarkOperations.CleanupContexts(this);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/_SystemWithTwoComponents.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 |
3 | namespace Ecs.CSharp.Benchmark
4 | {
5 | [BenchmarkCategory(Categories.System)]
6 | [MemoryDiagnoser]
7 | #if CHECK_CACHE_MISSES
8 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)]
9 | #endif
10 | public partial class SystemWithTwoComponents
11 | {
12 | [Params(100000)]
13 | public int EntityCount { get; set; }
14 |
15 | [Params(0, 10)]
16 | public int EntityPadding { get; set; }
17 |
18 | [GlobalSetup]
19 | public void Setup() => BenchmarkOperations.SetupContexts(this, EntityCount, EntityPadding);
20 |
21 | [GlobalCleanup]
22 | public void Cleanup() => BenchmarkOperations.CleanupContexts(this);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/LeopotamEcsLiteBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Leopotam.EcsLite;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | internal class LeopotamEcsLiteBaseContext : IDisposable
7 | {
8 | public struct Component1
9 | {
10 | public int Value;
11 | }
12 |
13 | public struct Component2
14 | {
15 | public int Value;
16 | }
17 |
18 | public struct Component3
19 | {
20 | public int Value;
21 | }
22 |
23 | public EcsWorld World { get; }
24 |
25 | public LeopotamEcsLiteBaseContext()
26 | {
27 | World = new EcsWorld();
28 | }
29 |
30 | public virtual void Dispose()
31 | {
32 | World.Destroy();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/TinyEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using DefaultEcs;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 | using Ecs.CSharp.Benchmark.Contexts.TinyEcs_Components;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class CreateEntityWithThreeComponents
9 | {
10 | [Context]
11 | private readonly TinyEcsBaseContext _tinyEcs;
12 |
13 | [BenchmarkCategory(Categories.TinyEcs)]
14 | [Benchmark]
15 | public void TinyEcs()
16 | {
17 | for (int i = 0; i < EntityCount; ++i)
18 | {
19 | _tinyEcs.World.Entity()
20 | .Set()
21 | .Set()
22 | .Set();
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/_SystemWithThreeComponents.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 |
3 | namespace Ecs.CSharp.Benchmark
4 | {
5 | [BenchmarkCategory(Categories.System)]
6 | [MemoryDiagnoser]
7 | #if CHECK_CACHE_MISSES
8 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)]
9 | #endif
10 | public partial class SystemWithThreeComponents
11 | {
12 | [Params(100000)]
13 | public int EntityCount { get; set; }
14 |
15 | [Params(0, 10)]
16 | public int EntityPadding { get; set; }
17 |
18 | [GlobalSetup]
19 | public void Setup() => BenchmarkOperations.SetupContexts(this, EntityCount, EntityPadding);
20 |
21 | [GlobalCleanup]
22 | public void Cleanup() => BenchmarkOperations.CleanupContexts(this);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.github/workflows/ContinuousIntegration.yml:
--------------------------------------------------------------------------------
1 | name: continuous integration
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | paths:
8 | - '.github/workflows/ContinuousIntegration.yml'
9 | - 'source/**'
10 |
11 | jobs:
12 | continuous_integration:
13 | runs-on: windows-latest
14 | steps:
15 | - name: Checkout
16 | uses: actions/checkout@v2
17 | with:
18 | ref: master
19 |
20 | - name: Set up dotnet
21 | uses: actions/setup-dotnet@v1
22 | with:
23 | dotnet-version: '8.0.x'
24 | source-url: https://nuget.pkg.github.com/Doraku/index.json
25 | env:
26 | NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
27 |
28 | - name: Run benchmark
29 | run: dotnet run --project source\Ecs.CSharp.Benchmark\Ecs.CSharp.Benchmark.csproj -c Release --filter * --job Dry
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/MorpehBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Scellecs.Morpeh;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | internal class MorpehBaseContext : IDisposable
7 | {
8 | public struct Component1 : IComponent
9 | {
10 | public int Value;
11 | }
12 |
13 | public struct Component2 : IComponent
14 | {
15 | public int Value;
16 | }
17 |
18 | public struct Component3 : IComponent
19 | {
20 | public int Value;
21 | }
22 |
23 | public World World { get; }
24 |
25 | public MorpehBaseContext()
26 | {
27 | World = World.Create();
28 | }
29 |
30 | public virtual void Dispose()
31 | {
32 | World.Dispose();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/FlecsNet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using BenchmarkDotNet.Attributes;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 | using Ecs.CSharp.Benchmark.Contexts.FlecsNet_Components;
5 | using Flecs.NET.Core;
6 |
7 | namespace Ecs.CSharp.Benchmark
8 | {
9 | public partial class CreateEntityWithOneComponent
10 | {
11 | [Context]
12 | private readonly FlecsNetBaseContext _flecs;
13 |
14 | [BenchmarkCategory(Categories.FlecsNet)]
15 | [Benchmark]
16 | public void FlecsNet()
17 | {
18 | World world = _flecs.World;
19 |
20 | for (int i = 0; i < EntityCount; ++i)
21 | {
22 | world.Entity()
23 | .Set(new());
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/LeopotamEcsLite.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.EcsLite;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithOneComponent
8 | {
9 | [Context]
10 | private readonly LeopotamEcsLiteBaseContext _leopotamEcsLite;
11 |
12 | [BenchmarkCategory(Categories.LeopotamEcsLite)]
13 | [Benchmark]
14 | public void LeopotamEcsLite()
15 | {
16 | EcsPool c1 = _leopotamEcsLite.World.GetPool();
17 |
18 | for (int i = 0; i < EntityCount; ++i)
19 | {
20 | c1.Add(_leopotamEcsLite.World.NewEntity());
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/FennecsBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using fennecs;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | namespace Fennecs_Components
7 | {
8 | internal struct Component1
9 | {
10 | public int Value;
11 | }
12 |
13 | internal struct Component2
14 | {
15 | public int Value;
16 | }
17 |
18 | internal struct Component3
19 | {
20 | public int Value;
21 | }
22 | }
23 |
24 | internal class FennecsBaseContext : IDisposable
25 | {
26 | public World World { get; }
27 |
28 | public FennecsBaseContext()
29 | {
30 | World = new World();
31 | }
32 |
33 | public void Dispose()
34 | {
35 | World.Dispose();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/FlecsNetBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Flecs.NET.Core;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | namespace FlecsNet_Components
7 | {
8 | internal struct Component1
9 | {
10 | public int Value;
11 | }
12 |
13 | internal struct Component2
14 | {
15 | public int Value;
16 | }
17 |
18 | internal struct Component3
19 | {
20 | public int Value;
21 | }
22 | }
23 |
24 | internal class FlecsNetBaseContext : IDisposable
25 | {
26 | public World World { get; }
27 |
28 | public FlecsNetBaseContext()
29 | {
30 | World = World.Create();
31 | }
32 |
33 | public void Dispose()
34 | {
35 | World.Dispose();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/FlecsNet.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
4 | using Flecs.NET.Core;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class CreateEntityWithTwoComponents
9 | {
10 | [Context]
11 | private readonly FlecsNetBaseContext _flecs;
12 |
13 | [BenchmarkCategory(Categories.FlecsNet)]
14 | [Benchmark]
15 | public void FlecsNet()
16 | {
17 | World world = _flecs.World;
18 |
19 | for (int i = 0; i < EntityCount; ++i)
20 | {
21 | world.Entity()
22 | .Set(new())
23 | .Set(new());
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/MonoGameExtendedBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using MonoGame.Extended.Entities;
3 |
4 | namespace Ecs.CSharp.Benchmark.Contexts
5 | {
6 | internal class MonoGameExtendedBaseContext : IDisposable
7 | {
8 | public sealed class Component1
9 | {
10 | public int Value;
11 | }
12 |
13 | public sealed class Component2
14 | {
15 | public int Value;
16 | }
17 |
18 | public sealed class Component3
19 | {
20 | public int Value;
21 | }
22 |
23 | public World World { get; }
24 |
25 | public MonoGameExtendedBaseContext()
26 | {
27 | World = new WorldBuilder().Build();
28 | }
29 |
30 | public virtual void Dispose()
31 | {
32 | World.Dispose();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/FrifloEngineEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts.FrifloEngine_Components;
3 | using Friflo.Engine.ECS;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithOneComponent
8 | {
9 | [BenchmarkCategory(Categories.FrifloEngineEcs)]
10 | [Benchmark]
11 | public void FrifloEngineEcs()
12 | {
13 | EntityStore store = new EntityStore(PidType.UsePidAsId);
14 | store.EnsureCapacity(EntityCount);
15 |
16 | Archetype archetype = store.GetArchetype(ComponentTypes.Get());
17 | archetype.EnsureCapacity(EntityCount);
18 |
19 | for (int i = 0; i < EntityCount; ++i)
20 | {
21 | archetype.CreateEntity();
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/DefaultEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using DefaultEcs;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithThreeComponents
8 | {
9 | [Context]
10 | private readonly DefaultEcsBaseContext _defaultEcs;
11 |
12 | [BenchmarkCategory(Categories.DefaultEcs)]
13 | [Benchmark]
14 | public void DefaultEcs()
15 | {
16 | for (int i = 0; i < EntityCount; ++i)
17 | {
18 | Entity entity = _defaultEcs.World.CreateEntity();
19 | entity.Set();
20 | entity.Set();
21 | entity.Set();
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/SveltoECS.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Svelto.ECS;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithOneComponent
8 | {
9 | private sealed class SveltoEntity : GenericEntityDescriptor
10 | { }
11 |
12 | [Context]
13 | private readonly SveltoECSBaseContext _sveltoECS;
14 |
15 | [BenchmarkCategory(Categories.SveltoECS)]
16 | [Benchmark]
17 | public void SveltoECS()
18 | {
19 | for (int i = 0; i < EntityCount; ++i)
20 | {
21 | _sveltoECS.Factory.BuildEntity((uint)i, SveltoECSBaseContext.Group);
22 | }
23 |
24 | _sveltoECS.Scheduler.SubmitEntities();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/MonoGameExtended.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using MonoGame.Extended.Entities;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithTwoComponents
8 | {
9 | [Context]
10 | private readonly MonoGameExtendedBaseContext _monoGameExtended;
11 |
12 | [BenchmarkCategory(Categories.MonoGameExtended)]
13 | [Benchmark]
14 | public void MonoGameExtended()
15 | {
16 | for (int i = 0; i < EntityCount; ++i)
17 | {
18 | Entity entity = _monoGameExtended.World.CreateEntity();
19 | entity.Attach(new MonoGameExtendedBaseContext.Component1());
20 | entity.Attach(new MonoGameExtendedBaseContext.Component2());
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/LeopotamEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.Ecs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithThreeComponents
8 | {
9 | [Context]
10 | private readonly LeopotamEcsBaseContext _leopotamEcs;
11 |
12 | [BenchmarkCategory(Categories.LeopotamEcs)]
13 | [Benchmark]
14 | public void LeopotamEcs()
15 | {
16 | for (int i = 0; i < EntityCount; ++i)
17 | {
18 | _leopotamEcs.World.NewEntity()
19 | .Replace(new LeopotamEcsBaseContext.Component1())
20 | .Replace(new LeopotamEcsBaseContext.Component2())
21 | .Replace(new LeopotamEcsBaseContext.Component3());
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/FrifloEngineEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts.FrifloEngine_Components;
3 | using Friflo.Engine.ECS;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithTwoComponents
8 | {
9 | [BenchmarkCategory(Categories.FrifloEngineEcs)]
10 | [Benchmark]
11 | public void FrifloEngineEcs()
12 | {
13 | EntityStore store = new EntityStore(PidType.UsePidAsId);
14 | store.EnsureCapacity(EntityCount);
15 |
16 | Archetype archetype = store.GetArchetype(ComponentTypes.Get());
17 | archetype.EnsureCapacity(EntityCount);
18 |
19 | for (int i = 0; i < EntityCount; ++i)
20 | {
21 | archetype.CreateEntity();
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/Fennecs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.Fennecs_Components;
4 | using fennecs;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class CreateEntityWithThreeComponents
9 | {
10 | [Context]
11 | private readonly FennecsBaseContext _fennecs;
12 |
13 | [BenchmarkCategory(Categories.Fennecs)]
14 | [Benchmark]
15 | public void Fennecs()
16 | {
17 | World world = _fennecs.World;
18 |
19 | for (int i = 0; i < EntityCount; ++i)
20 | {
21 | world.Spawn()
22 | .Add()
23 | .Add()
24 | .Add();
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/FrifloEngineEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts.FrifloEngine_Components;
3 | using Friflo.Engine.ECS;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithThreeComponents
8 | {
9 | [BenchmarkCategory(Categories.FrifloEngineEcs)]
10 | [Benchmark]
11 | public void FrifloEngineEcs()
12 | {
13 | EntityStore store = new EntityStore(PidType.UsePidAsId);
14 | store.EnsureCapacity(EntityCount);
15 |
16 | Archetype archetype = store.GetArchetype(ComponentTypes.Get());
17 | archetype.EnsureCapacity(EntityCount);
18 |
19 | for (int i = 0; i < EntityCount; ++i)
20 | {
21 | archetype.CreateEntity();
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/SveltoECS.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Svelto.ECS;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithThreeComponents
8 | {
9 | private sealed class SveltoEntity : GenericEntityDescriptor
10 | { }
11 |
12 | [Context]
13 | private readonly SveltoECSBaseContext _sveltoECS;
14 |
15 | [Benchmark]
16 | public void SveltoECS()
17 | {
18 | for (int i = 0; i < EntityCount; ++i)
19 | {
20 | _sveltoECS.Factory.BuildEntity((uint)i, SveltoECSBaseContext.Group);
21 | }
22 |
23 | _sveltoECS.Scheduler.SubmitEntities();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/FlecsNet.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
4 | using Flecs.NET.Core;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class CreateEntityWithThreeComponents
9 | {
10 | [Context]
11 | private readonly FlecsNetBaseContext _flecs;
12 |
13 | [BenchmarkCategory(Categories.FlecsNet)]
14 | [Benchmark]
15 | public void FlecsNet()
16 | {
17 | World world = _flecs.World;
18 |
19 | for (int i = 0; i < EntityCount; ++i)
20 | {
21 | world.Entity()
22 | .Set(new())
23 | .Set(new())
24 | .Set(new());
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/Arch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Arch.Core;
3 | using Arch.Core.Utils;
4 | using BenchmarkDotNet.Attributes;
5 | using Ecs.CSharp.Benchmark.Contexts;
6 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
7 |
8 | namespace Ecs.CSharp.Benchmark
9 | {
10 | public partial class CreateEntityWithOneComponent
11 | {
12 | private static readonly ComponentType[] _archetype = [typeof(Component1)];
13 |
14 | [Context]
15 | private readonly ArchBaseContext _arch;
16 |
17 | [BenchmarkCategory(Categories.Arch)]
18 | [Benchmark]
19 | public void Arch()
20 | {
21 | World world = _arch.World;
22 | world.Reserve(_archetype, EntityCount);
23 |
24 | for (int i = 0; i < EntityCount; ++i)
25 | {
26 | world.Create(_archetype);
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/SveltoECS.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Svelto.ECS;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithTwoComponents
8 | {
9 | private sealed class SveltoEntity : GenericEntityDescriptor
10 | { }
11 |
12 | [Context]
13 | private readonly SveltoECSBaseContext _sveltoECS;
14 |
15 | [BenchmarkCategory(Categories.SveltoECS)]
16 | [Benchmark]
17 | public void SveltoECS()
18 | {
19 | for (int i = 0; i < EntityCount; ++i)
20 | {
21 | _sveltoECS.Factory.BuildEntity((uint)i, SveltoECSBaseContext.Group);
22 | }
23 |
24 | _sveltoECS.Scheduler.SubmitEntities();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/Myriad.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using BenchmarkDotNet.Attributes;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 | using Ecs.CSharp.Benchmark.Contexts.Myriad_Components;
5 | using Myriad.ECS.Command;
6 | using Myriad.ECS.Worlds;
7 |
8 | namespace Ecs.CSharp.Benchmark
9 | {
10 | public partial class CreateEntityWithOneComponent
11 | {
12 | [Context]
13 | private readonly MyriadBaseContext _myriad;
14 |
15 | [BenchmarkCategory(Categories.Myriad)]
16 | [Benchmark]
17 | public void Myriad()
18 | {
19 | World world = _myriad.World;
20 |
21 | CommandBuffer buffer = new CommandBuffer(world);
22 |
23 | for (int i = 0; i < EntityCount; ++i)
24 | {
25 | buffer.Create().Set(new Component1());
26 | }
27 |
28 | buffer.Playback().Dispose();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/Arch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Arch.Core;
3 | using Arch.Core.Utils;
4 | using BenchmarkDotNet.Attributes;
5 | using Ecs.CSharp.Benchmark.Contexts;
6 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
7 |
8 | namespace Ecs.CSharp.Benchmark
9 | {
10 | public partial class CreateEntityWithTwoComponents
11 | {
12 | private static readonly ComponentType[] _archetype = [typeof(Component1), typeof(Component2)];
13 |
14 | [Context]
15 | private readonly ArchBaseContext _arch;
16 |
17 | [BenchmarkCategory(Categories.Arch)]
18 | [Benchmark]
19 | public void Arch()
20 | {
21 | World world = _arch.World;
22 | world.Reserve(_archetype, EntityCount);
23 |
24 | for (int i = 0; i < EntityCount; ++i)
25 | {
26 | world.Create(_archetype);
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/Arch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Arch.Core.Utils;
3 | using BenchmarkDotNet.Attributes;
4 | using Ecs.CSharp.Benchmark.Contexts;
5 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
6 |
7 | namespace Ecs.CSharp.Benchmark
8 | {
9 | public partial class CreateEntityWithThreeComponents
10 | {
11 | private static readonly ComponentType[] _archetype = [typeof(Component1), typeof(Component2), typeof(Component3)];
12 |
13 | [Context]
14 | private readonly ArchBaseContext _arch;
15 |
16 | [BenchmarkCategory(Categories.Arch)]
17 | [Benchmark]
18 | public void Arch()
19 | {
20 | Arch.Core.World world = _arch.World;
21 | world.Reserve(_archetype, EntityCount);
22 |
23 | for (int i = 0; i < EntityCount; ++i)
24 | {
25 | world.Create(_archetype);
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/Myriad.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using BenchmarkDotNet.Attributes;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 | using Ecs.CSharp.Benchmark.Contexts.Myriad_Components;
5 | using Myriad.ECS.Command;
6 | using Myriad.ECS.Worlds;
7 |
8 | namespace Ecs.CSharp.Benchmark
9 | {
10 | public partial class CreateEntityWithTwoComponents
11 | {
12 | [Context]
13 | private readonly MyriadBaseContext _myriad;
14 |
15 | [BenchmarkCategory(Categories.Myriad)]
16 | [Benchmark]
17 | public void Myriad()
18 | {
19 | World world = _myriad.World;
20 |
21 | CommandBuffer buffer = new CommandBuffer(world);
22 |
23 | for (int i = 0; i < EntityCount; ++i)
24 | {
25 | buffer.Create().Set(new Component1()).Set(new Component2());
26 | }
27 |
28 | buffer.Playback().Dispose();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT No Attribution
2 |
3 | Copyright (c) 2021 Paillat Laszlo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 | SOFTWARE.
19 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/MonoGameExtended.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using MonoGame.Extended.Entities;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithThreeComponents
8 | {
9 | [Context]
10 | private readonly MonoGameExtendedBaseContext _monoGameExtended;
11 |
12 | [BenchmarkCategory(Categories.MonoGameExtended)]
13 | [Benchmark]
14 | public void MonoGameExtended()
15 | {
16 | for (int i = 0; i < EntityCount; ++i)
17 | {
18 | Entity entity = _monoGameExtended.World.CreateEntity();
19 | entity.Attach(new MonoGameExtendedBaseContext.Component1());
20 | entity.Attach(new MonoGameExtendedBaseContext.Component2());
21 | entity.Attach(new MonoGameExtendedBaseContext.Component3());
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/Myriad.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using BenchmarkDotNet.Attributes;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 | using Ecs.CSharp.Benchmark.Contexts.Myriad_Components;
5 | using Myriad.ECS.Command;
6 | using Myriad.ECS.Worlds;
7 |
8 | namespace Ecs.CSharp.Benchmark
9 | {
10 | public partial class CreateEntityWithThreeComponents
11 | {
12 | [Context]
13 | private readonly MyriadBaseContext _myriad;
14 |
15 | [BenchmarkCategory(Categories.Myriad)]
16 | [Benchmark]
17 | public void Myriad()
18 | {
19 | World world = _myriad.World;
20 |
21 | CommandBuffer buffer = new CommandBuffer(world);
22 |
23 | for (int i = 0; i < EntityCount; ++i)
24 | {
25 | buffer.Create().Set(new Component1()).Set(new Component2()).Set(new Component3());
26 | }
27 |
28 | buffer.Playback().Dispose();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/LeopotamEcsLite.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.EcsLite;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithTwoComponents
8 | {
9 | [Context]
10 | private readonly LeopotamEcsLiteBaseContext _leopotamEcsLite;
11 |
12 | [BenchmarkCategory(Categories.LeopotamEcsLite)]
13 | [Benchmark]
14 | public void LeopotamEcsLite()
15 | {
16 | EcsPool c1 = _leopotamEcsLite.World.GetPool();
17 | EcsPool c2 = _leopotamEcsLite.World.GetPool();
18 |
19 | for (int i = 0; i < EntityCount; ++i)
20 | {
21 | int entity = _leopotamEcsLite.World.NewEntity();
22 | c1.Add(entity);
23 | c2.Add(entity);
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Categories.cs:
--------------------------------------------------------------------------------
1 | namespace Ecs.CSharp.Benchmark
2 | {
3 | internal static class Categories
4 | {
5 | public const string Arch = "Arch";
6 | public const string DefaultEcs = "DefaultEcs";
7 | public const string Frent = "Frent";
8 | public const string FrifloEngineEcs = "FrifloEngineEcs";
9 | public const string HypEcs = "HypEcs";
10 | public const string LeopotamEcs = "Leopotam.Ecs";
11 | public const string LeopotamEcsLite = "Leopotam.EcsLite";
12 | public const string MonoGameExtended = "MonoGame.Extended";
13 | public const string Myriad = "Myriad.ECS";
14 | public const string RelEcs = "RelEcs";
15 | public const string SveltoECS = "Svelto.ECS";
16 | public const string Morpeh = "Morpeh";
17 | public const string FlecsNet = "FlecsNet";
18 | public const string Fennecs = "Fennecs";
19 | public const string TinyEcs = "TinyEcs";
20 |
21 | public const string CreateEntity = "CreateEntity";
22 | public const string System = "System";
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/BenchmarkOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | internal static class BenchmarkOperations
9 | {
10 | private static readonly MethodInfo _disposeMethod = typeof(IDisposable).GetMethod(nameof(IDisposable.Dispose));
11 |
12 | private static IEnumerable GetContextFields() => typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(f => f.GetCustomAttribute() != null);
13 |
14 | public static void SetupContexts(T benchmark, params object[] args)
15 | {
16 | foreach (FieldInfo field in GetContextFields())
17 | {
18 | field.SetValue(benchmark, Activator.CreateInstance(field.FieldType, args));
19 | }
20 | }
21 |
22 | public static void CleanupContexts(T benchmark)
23 | {
24 | foreach (FieldInfo field in GetContextFields())
25 | {
26 | _disposeMethod.Invoke(field.GetValue(benchmark), null);
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/LeopotamEcsLite.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.EcsLite;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithThreeComponents
8 | {
9 | [Context]
10 | private readonly LeopotamEcsLiteBaseContext _leopotamEcsLite;
11 |
12 | [BenchmarkCategory(Categories.LeopotamEcsLite)]
13 | [Benchmark]
14 | public void LeopotamEcsLite()
15 | {
16 | EcsPool c1 = _leopotamEcsLite.World.GetPool();
17 | EcsPool c2 = _leopotamEcsLite.World.GetPool();
18 | EcsPool c3 = _leopotamEcsLite.World.GetPool();
19 |
20 | for (int i = 0; i < EntityCount; ++i)
21 | {
22 | int entity = _leopotamEcsLite.World.NewEntity();
23 | c1.Add(entity);
24 | c2.Add(entity);
25 | c3.Add(entity);
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/SveltoECSBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Svelto.ECS;
3 | using Svelto.ECS.Schedulers;
4 |
5 | namespace Ecs.CSharp.Benchmark.Contexts
6 | {
7 | internal class SveltoECSBaseContext : IDisposable
8 | {
9 | public struct Component1 : IEntityComponent
10 | {
11 | public int Value;
12 | }
13 |
14 | public struct Component2 : IEntityComponent
15 | {
16 | public int Value;
17 | }
18 |
19 | public struct Component3 : IEntityComponent
20 | {
21 | public int Value;
22 | }
23 |
24 | public static ExclusiveGroup Group { get; } = new();
25 |
26 | public SimpleEntitiesSubmissionScheduler Scheduler { get; }
27 | public EnginesRoot Root { get; }
28 | public IEntityFactory Factory { get; }
29 |
30 | public SveltoECSBaseContext()
31 | {
32 | Scheduler = new SimpleEntitiesSubmissionScheduler();
33 | Root = new EnginesRoot(Scheduler);
34 | Factory = Root.GenerateEntityFactory();
35 | }
36 |
37 | public virtual void Dispose()
38 | {
39 | Root.Dispose();
40 | Scheduler.Dispose();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/Frent.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Frent;
4 | using Frent.Core;
5 | using static Ecs.CSharp.Benchmark.Contexts.FrentBaseContext;
6 |
7 | namespace Ecs.CSharp.Benchmark
8 | {
9 | public partial class CreateEntityWithOneComponent
10 | {
11 | private static readonly EntityType _entityType = Entity.EntityTypeOf([Component.ID], []);
12 |
13 | [Context]
14 | private readonly FrentBaseContext _frent;
15 |
16 | [BenchmarkCategory(Categories.Frent)]
17 | [Benchmark]
18 | public void Frent()
19 | {
20 | World world = _frent.World;
21 | world.EnsureCapacity(_entityType, EntityCount);
22 |
23 | for (int i = 0; i < EntityCount; i++)
24 | world.Create(default);
25 | }
26 |
27 | [BenchmarkCategory(Categories.Frent)]
28 | [Benchmark]
29 | public void Frent_Bulk()
30 | {
31 | World world = _frent.World;
32 | var chunks = world.CreateMany(EntityCount);
33 |
34 | for (int i = 0; i < chunks.Span.Length; i++)
35 | chunks.Span[i] = new();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Program.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable CA1852 // Seal internal types
2 |
3 | using System.Globalization;
4 | using BenchmarkDotNet.Configs;
5 | using BenchmarkDotNet.Order;
6 | using BenchmarkDotNet.Running;
7 | using Ecs.CSharp.Benchmark;
8 |
9 | CultureInfo cultureInfo = new("en-US");
10 |
11 | CultureInfo.CurrentCulture = cultureInfo;
12 | CultureInfo.CurrentUICulture = cultureInfo;
13 | CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
14 | CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
15 |
16 | BenchmarkSwitcher benchmark = BenchmarkSwitcher.FromTypes(new[]
17 | {
18 | typeof(CreateEntityWithOneComponent),
19 | typeof(CreateEntityWithTwoComponents),
20 | typeof(CreateEntityWithThreeComponents),
21 |
22 | typeof(SystemWithOneComponent),
23 | typeof(SystemWithTwoComponents),
24 | typeof(SystemWithThreeComponents),
25 |
26 | typeof(SystemWithTwoComponentsMultipleComposition)
27 | });
28 |
29 | IConfig configuration = DefaultConfig.Instance
30 | .WithOptions(ConfigOptions.DisableOptimizationsValidator)
31 | .WithOrderer(new DefaultOrderer(SummaryOrderPolicy.FastestToSlowest));
32 |
33 | if (args.Length > 0)
34 | {
35 | benchmark.Run(args, configuration);
36 | }
37 | else
38 | {
39 | benchmark.RunAll(configuration);
40 | }
41 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithOneComponent/Morpeh.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Scellecs.Morpeh;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithOneComponent
8 | {
9 | [Context]
10 | private readonly MorpehBaseContext _context;
11 |
12 | [BenchmarkCategory(Categories.Morpeh)]
13 | [Benchmark]
14 | public void Morpeh_Direct()
15 | {
16 | World world = _context.World;
17 | for (int i = 0; i < EntityCount; ++i)
18 | {
19 | world.CreateEntity().AddComponent();
20 | }
21 |
22 | world.Commit();
23 | }
24 |
25 | [BenchmarkCategory(Categories.Morpeh)]
26 | [Benchmark]
27 | public void Morpeh_Stash()
28 | {
29 | World world = _context.World;
30 | Stash stash1 = world.GetStash();
31 | for (int i = 0; i < EntityCount; ++i)
32 | {
33 | Entity entity = world.CreateEntity();
34 | stash1.Add(entity);
35 | }
36 |
37 | world.Commit();
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/MyriadBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using Myriad.ECS;
4 | using Myriad.ECS.Worlds;
5 |
6 | namespace Ecs.CSharp.Benchmark.Contexts
7 | {
8 | namespace Myriad_Components
9 | {
10 | internal struct Component1
11 | : IComponent
12 | {
13 | public int Value;
14 | }
15 |
16 | internal struct Component2
17 | : IComponent
18 | {
19 | public int Value;
20 | }
21 |
22 | internal struct Component3
23 | : IComponent
24 | {
25 | public int Value;
26 | }
27 |
28 | internal struct Padding1
29 | : IComponent
30 | {
31 | }
32 |
33 | internal struct Padding2
34 | : IComponent
35 | {
36 | }
37 |
38 | internal struct Padding3
39 | : IComponent
40 | {
41 | }
42 |
43 | internal struct Padding4
44 | : IComponent
45 | {
46 | }
47 | }
48 |
49 | internal class MyriadBaseContext
50 | : IDisposable
51 | {
52 | public World World { get; }
53 |
54 | public MyriadBaseContext()
55 | {
56 | World = new WorldBuilder().Build();
57 | }
58 |
59 | public void Dispose()
60 | {
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/Frent.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Frent;
4 | using Frent.Core;
5 | using static Ecs.CSharp.Benchmark.Contexts.FrentBaseContext;
6 |
7 | namespace Ecs.CSharp.Benchmark
8 | {
9 | public partial class CreateEntityWithTwoComponents
10 | {
11 | private static readonly EntityType _entityType = Entity.EntityTypeOf([Component.ID, Component.ID], []);
12 |
13 | [Context]
14 | private readonly FrentBaseContext _frent;
15 |
16 | [BenchmarkCategory(Categories.Frent)]
17 | [Benchmark]
18 | public void Frent()
19 | {
20 | World world = _frent.World;
21 | world.EnsureCapacity(_entityType, EntityCount);
22 |
23 | for (int i = 0; i < EntityCount; i++)
24 | world.Create(default, default);
25 | }
26 |
27 | [BenchmarkCategory(Categories.Frent)]
28 | [Benchmark]
29 | public void Frent_Bulk()
30 | {
31 | World world = _frent.World;
32 | var chunks = world.CreateMany(EntityCount);
33 |
34 | chunks.Span2 = chunks.Span2[..chunks.Span1.Length];
35 | for (int i = 0; i < chunks.Span1.Length; i++)
36 | {
37 | chunks.Span1[i] = default;
38 | chunks.Span2[i] = default;
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/TinyEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.TinyEcs_Components;
4 | using TinyEcs;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class SystemWithOneComponent
9 | {
10 | [Context] private readonly TinyEcsContext _tinyEcs;
11 |
12 | private sealed class TinyEcsContext : TinyEcsBaseContext
13 | {
14 | public Query Query { get; }
15 | public TinyEcsContext(int entityCount, int entityPadding) : base()
16 | {
17 | for (int i = 0; i < entityCount; ++i)
18 | {
19 | for (int j = 0; j < entityPadding; ++j)
20 | {
21 | World.Entity();
22 | }
23 |
24 | World.Entity().Set();
25 | }
26 |
27 | Query = World.Query();
28 | }
29 | }
30 |
31 | [BenchmarkCategory(Categories.TinyEcs)]
32 | [Benchmark]
33 | public void TinyEcs_Each()
34 | {
35 | _tinyEcs.Query.Each((ref Component1 c1) => c1.Value++);
36 | }
37 |
38 | [BenchmarkCategory(Categories.TinyEcs)]
39 | [Benchmark]
40 | public void TinyEcs_EachJob()
41 | {
42 | _tinyEcs.Query.EachJob((ref Component1 c1) => c1.Value++);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/Morpeh.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Scellecs.Morpeh;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithThreeComponents
8 | {
9 | [Context]
10 | private readonly MorpehBaseContext _context;
11 |
12 | [BenchmarkCategory(Categories.Morpeh)]
13 | [Benchmark]
14 | public void Morpeh_Direct()
15 | {
16 | World world = _context.World;
17 | for (int i = 0; i < EntityCount; ++i)
18 | {
19 | world.CreateEntity().AddComponent();
20 | world.CreateEntity().AddComponent();
21 | }
22 |
23 | world.Commit();
24 | }
25 |
26 | [BenchmarkCategory(Categories.Morpeh)]
27 | [Benchmark]
28 | public void Morpeh_Stash()
29 | {
30 | World world = _context.World;
31 | Stash stash1 = world.GetStash();
32 | Stash stash2 = world.GetStash();
33 | for (int i = 0; i < EntityCount; ++i)
34 | {
35 | Entity entity = world.CreateEntity();
36 | stash1.Add(entity);
37 | stash2.Add(entity);
38 | }
39 |
40 | world.Commit();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/RelEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using RelEcs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class SystemWithOneComponent
8 | {
9 | private sealed class RelEcsContext : RelEcsBaseContext
10 | {
11 | private sealed class MonoThreadRunSystem : ISystem
12 | {
13 | public void Run(World world)
14 | {
15 | foreach (Component1 c in world.Query().Build())
16 | {
17 | c.Value++;
18 | }
19 | }
20 | }
21 |
22 | public ISystem MonoThreadSystem { get; } = new MonoThreadRunSystem();
23 |
24 | public RelEcsContext(int entityCount, int entityPadding)
25 | {
26 | for (int i = 0; i < entityCount; ++i)
27 | {
28 | for (int j = 0; j < entityPadding; ++j)
29 | {
30 | World.Spawn();
31 | }
32 |
33 | World
34 | .Spawn()
35 | .Add(new Component1());
36 | }
37 | }
38 | }
39 |
40 | [Context]
41 | private readonly RelEcsContext _relEcs;
42 |
43 | [BenchmarkCategory(Categories.RelEcs)]
44 | [Benchmark]
45 | public void RelEcs() => _relEcs.MonoThreadSystem.Run(_relEcs.World);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithThreeComponents/Frent.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Frent;
4 | using Frent.Core;
5 | using static Ecs.CSharp.Benchmark.Contexts.FrentBaseContext;
6 |
7 | namespace Ecs.CSharp.Benchmark
8 | {
9 | public partial class CreateEntityWithThreeComponents
10 | {
11 | private static readonly EntityType _entityType = Entity.EntityTypeOf([Component.ID, Component.ID, Component.ID], []);
12 |
13 | [Context]
14 | private readonly FrentBaseContext _frent;
15 |
16 | [BenchmarkCategory(Categories.Frent)]
17 | [Benchmark]
18 | public void Frent()
19 | {
20 | World world = _frent.World;
21 | world.EnsureCapacity(_entityType, EntityCount);
22 |
23 | for (int i = 0; i < EntityCount; i++)
24 | world.Create(default, default, default);
25 | }
26 |
27 | [BenchmarkCategory(Categories.Frent)]
28 | [Benchmark]
29 | public void Frent_Bulk()
30 | {
31 | World world = _frent.World;
32 | var chunks = world.CreateMany(EntityCount);
33 |
34 | chunks.Span2 = chunks.Span2[..chunks.Span1.Length];
35 | chunks.Span3 = chunks.Span3[..chunks.Span1.Length];
36 | for (int i = 0; i < chunks.Span1.Length; i++)
37 | {
38 | chunks.Span1[i] = default;
39 | chunks.Span2[i] = default;
40 | chunks.Span3[i] = default;
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/Contexts/ArchBaseContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Arch.Core;
3 | using Arch.Core.Utils;
4 | using Schedulers;
5 |
6 | namespace Ecs.CSharp.Benchmark.Contexts
7 | {
8 | namespace Arch_Components
9 | {
10 | internal struct Component1
11 | {
12 | public int Value;
13 | }
14 |
15 | internal struct Component2
16 | {
17 | public int Value;
18 | }
19 |
20 | internal struct Component3
21 | {
22 | public int Value;
23 | }
24 | }
25 |
26 | internal class ArchBaseContext : IDisposable
27 | {
28 | public World World { get; }
29 | public JobScheduler JobScheduler { get; set; }
30 |
31 | public ArchBaseContext()
32 | {
33 | World = World.Create();
34 | }
35 |
36 | public ArchBaseContext(ComponentType[] archetype, int amount)
37 | {
38 | JobScheduler = new JobScheduler(new JobScheduler.Config
39 | {
40 | ThreadPrefixName = "Arch.Samples",
41 | ThreadCount = 0,
42 | MaxExpectedConcurrentJobs = 64,
43 | StrictAllocationMode = false,
44 | });
45 |
46 | World = World.Create();
47 | World.SharedJobScheduler = JobScheduler;
48 | World.Reserve(archetype, amount);
49 |
50 | for (int index = 0; index < amount; index++)
51 | {
52 | World.Create(archetype);
53 | }
54 | }
55 |
56 | public virtual void Dispose()
57 | {
58 | World.Destroy(World);
59 | JobScheduler?.Dispose();
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/CreateEntityWithTwoComponents/Morpeh.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Scellecs.Morpeh;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class CreateEntityWithTwoComponents
8 | {
9 | [Context]
10 | private readonly MorpehBaseContext _context;
11 |
12 | [BenchmarkCategory(Categories.Morpeh)]
13 | [Benchmark]
14 | public void Morpeh_Direct()
15 | {
16 | World world = _context.World;
17 | for (int i = 0; i < EntityCount; ++i)
18 | {
19 | world.CreateEntity().AddComponent();
20 | world.CreateEntity().AddComponent();
21 | world.CreateEntity().AddComponent();
22 | }
23 |
24 | world.Commit();
25 | }
26 |
27 | [BenchmarkCategory(Categories.Morpeh)]
28 | [Benchmark]
29 | public void Morpeh_Stash()
30 | {
31 | World world = _context.World;
32 | Stash stash1 = world.GetStash();
33 | Stash stash2 = world.GetStash();
34 | Stash stash3 = world.GetStash();
35 | for (int i = 0; i < EntityCount; ++i)
36 | {
37 | Entity entity = world.CreateEntity();
38 | stash1.Add(entity);
39 | stash2.Add(entity);
40 | stash3.Add(entity);
41 | }
42 |
43 | world.Commit();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/FlecsNet.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
4 | using Flecs.NET.Core;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class SystemWithOneComponent
9 | {
10 | [Context]
11 | private readonly FlecsContext _flecs;
12 |
13 | private sealed class FlecsContext : FlecsNetBaseContext
14 | {
15 | public Query query;
16 |
17 | public FlecsContext(int entityCount, int entityPadding)
18 | {
19 | for (int i = 0; i < entityCount; ++i)
20 | {
21 | for (int j = 0; j < entityPadding; ++j)
22 | {
23 | World.Entity();
24 | }
25 |
26 | World.Entity().Add();
27 |
28 | }
29 | query = World.QueryBuilder().With().Build();
30 | }
31 | }
32 |
33 | [BenchmarkCategory(Categories.FlecsNet)]
34 | [Benchmark]
35 | public void FlecsNet_Each()
36 | {
37 | _flecs.query.Each((ref Component1 c1) =>
38 | {
39 | c1.Value += 1;
40 | });
41 | }
42 |
43 | [BenchmarkCategory(Categories.FlecsNet)]
44 | [Benchmark]
45 | public void FlecsNet_Iter()
46 | {
47 | _flecs.query.Iter((Iter it, Column c1) =>
48 | {
49 | foreach (int i in it)
50 | {
51 | c1[i].Value += 1;
52 | }
53 | });
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/LeopotamEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.Ecs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class SystemWithOneComponent
8 | {
9 | private sealed class LeopotamEcsContext : LeopotamEcsBaseContext
10 | {
11 | private sealed class MonoThreadRunSystem : IEcsRunSystem
12 | {
13 | private readonly EcsFilter _filter;
14 |
15 | public void Run()
16 | {
17 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++)
18 | {
19 | ++_filter.Get1(i).Value;
20 | }
21 | }
22 | }
23 |
24 | public EcsSystems MonoThreadSystem { get; }
25 |
26 | public LeopotamEcsContext(int entityCount, int entityPadding)
27 | {
28 | MonoThreadSystem = new EcsSystems(World).Add(new MonoThreadRunSystem()).ProcessInjects();
29 |
30 | MonoThreadSystem.Init();
31 |
32 | for (int i = 0; i < entityCount; ++i)
33 | {
34 | for (int j = 0; j < entityPadding; ++j)
35 | {
36 | World.NewEntity();
37 | }
38 |
39 | World.NewEntity()
40 | .Replace(new Component1());
41 | }
42 | }
43 | }
44 |
45 | [Context]
46 | private readonly LeopotamEcsContext _leopotamEcs;
47 |
48 | [BenchmarkCategory(Categories.LeopotamEcs)]
49 | [Benchmark]
50 | public void LeopotamEcs() => _leopotamEcs.MonoThreadSystem.Run();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/Fennecs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 | using BenchmarkDotNet.Attributes;
4 | using Ecs.CSharp.Benchmark.Contexts;
5 | using Ecs.CSharp.Benchmark.Contexts.Fennecs_Components;
6 | using fennecs;
7 |
8 | namespace Ecs.CSharp.Benchmark
9 | {
10 | public partial class SystemWithOneComponent
11 | {
12 | [Context] private readonly FennecsContext _fennecs;
13 |
14 | private sealed class FennecsContext : FennecsBaseContext
15 | {
16 | public Query query;
17 |
18 | public FennecsContext(int entityCount, int entityPadding)
19 | {
20 | query = World.Query().Build();
21 | for (int i = 0; i < entityCount; ++i)
22 | {
23 | for (int j = 0; j < entityPadding; ++j)
24 | {
25 | World.Spawn();
26 | }
27 |
28 | World.Spawn().Add();
29 | }
30 | }
31 | }
32 |
33 | [BenchmarkCategory(Categories.Fennecs)]
34 | [Benchmark]
35 | public void Fennecs_ForEach()
36 | {
37 | _fennecs.query.For((ref Component1 comp0) => comp0.Value++);
38 | }
39 |
40 | [BenchmarkCategory(Categories.Fennecs)]
41 | [Benchmark]
42 | public void Fennecs_Job()
43 | {
44 | _fennecs.query.Job(delegate(ref Component1 v) { v.Value++; }, 1024);
45 | }
46 |
47 | [BenchmarkCategory(Categories.Fennecs)]
48 | [Benchmark]
49 | public void Fennecs_Raw()
50 | {
51 | _fennecs.query.Raw(delegate(Memory vectors)
52 | {
53 | foreach (ref var v in vectors.Span)
54 | {
55 | v.Value++;
56 | }
57 | });
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/TinyEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.TinyEcs_Components;
4 | using TinyEcs;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class SystemWithTwoComponents
9 | {
10 | [Context] private readonly TinyEcsContext _tinyEcs;
11 |
12 | private sealed class TinyEcsContext : TinyEcsBaseContext
13 | {
14 | public Query Query { get; }
15 |
16 | public TinyEcsContext(int entityCount, int entityPadding) : base()
17 | {
18 | for (int i = 0; i < entityCount; ++i)
19 | {
20 | for (int j = 0; j < entityPadding; ++j)
21 | {
22 | var padding = World.Entity();
23 | switch (j % 2)
24 | {
25 | case 0:
26 | padding.Set(new Component1());
27 | break;
28 |
29 | case 1:
30 | padding.Set(new Component2());
31 | break;
32 | }
33 | }
34 |
35 | World.Entity()
36 | .Set(new Component1())
37 | .Set(new Component2 { Value = 1 });
38 | Query = World.QueryBuilder().With().With().Build();
39 | }
40 | }
41 | }
42 |
43 | [BenchmarkCategory(Categories.TinyEcs)]
44 | [Benchmark]
45 | public void TinyEcs_Each()
46 | {
47 | _tinyEcs.Query.Each((ref Component1 c1, ref Component2 c2) => c1.Value += c2.Value);
48 | }
49 |
50 | [BenchmarkCategory(Categories.TinyEcs)]
51 | [Benchmark]
52 | public void TinyEcs_EachJob()
53 | {
54 | _tinyEcs.Query.EachJob((ref Component1 c1, ref Component2 c2) => c1.Value += c2.Value);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/RelEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using RelEcs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class SystemWithTwoComponents
8 | {
9 | private sealed class RelEcsContext : RelEcsBaseContext
10 | {
11 | private sealed class MonoThreadRunSystem : ISystem
12 | {
13 | public void Run(World world)
14 | {
15 | Query query = world.Query().Build();
16 | foreach ((Component1 c1, Component2 c2) in query)
17 | {
18 | c1.Value += c2.Value;
19 | }
20 | }
21 | }
22 |
23 | public ISystem MonoThreadSystem { get; } = new MonoThreadRunSystem();
24 |
25 | public RelEcsContext(int entityCount, int entityPadding)
26 | {
27 | for (int i = 0; i < entityCount; ++i)
28 | {
29 | for (int j = 0; j < entityPadding; ++j)
30 | {
31 | EntityBuilder padding = World.Spawn();
32 | switch (j % 2)
33 | {
34 | case 0:
35 | padding.Add(new Component1());
36 | break;
37 |
38 | case 1:
39 | padding.Add(new Component2());
40 | break;
41 | }
42 | }
43 |
44 | World.Spawn()
45 | .Add(new Component1())
46 | .Add(new Component2 { Value = 1 });
47 | }
48 | }
49 | }
50 |
51 | [Context]
52 | private readonly RelEcsContext _relEcs;
53 |
54 | [BenchmarkCategory(Categories.RelEcs)]
55 | [Benchmark]
56 | public void RelEcs() => _relEcs.MonoThreadSystem.Run(_relEcs.World);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/Arch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 | using Arch.Core;
4 | using Arch.Core.Utils;
5 | using Arch.System;
6 | using BenchmarkDotNet.Attributes;
7 | using Ecs.CSharp.Benchmark.Contexts;
8 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
9 |
10 | namespace Ecs.CSharp.Benchmark
11 | {
12 | public partial class SystemWithOneComponent
13 | {
14 | private struct ForEach1 : IForEach
15 | {
16 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
17 | public void Update(ref Component1 t0)
18 | {
19 | ++t0.Value;
20 | }
21 | }
22 |
23 | [Query]
24 | private static void ForEach(ref Component1 t0)
25 | {
26 | ++t0.Value;
27 | }
28 |
29 | private sealed class ArchContext : ArchBaseContext
30 | {
31 | public ArchContext(int entityCount, int _)
32 | : base(_filter, entityCount)
33 | { }
34 | }
35 |
36 | private static readonly ComponentType[] _filter = [typeof(Component1)];
37 | private static readonly QueryDescription _queryDescription = new() { All = _filter };
38 |
39 | [Context]
40 | private readonly ArchContext _arch;
41 | private ForEach1 _forEach;
42 |
43 | [BenchmarkCategory(Categories.Arch)]
44 | [Benchmark]
45 | public void Arch_MonoThread()
46 | {
47 | World world = _arch.World;
48 | world.InlineQuery(_queryDescription, ref _forEach);
49 | }
50 |
51 | [BenchmarkCategory(Categories.Arch)]
52 | [Benchmark]
53 | public void Arch_MonoThread_SourceGenerated()
54 | {
55 | ForEachQuery(_arch.World);
56 | }
57 |
58 | [BenchmarkCategory(Categories.Arch)]
59 | [Benchmark]
60 | public void Arch_MultiThread()
61 | {
62 | World world = _arch.World;
63 | world.InlineParallelQuery(_queryDescription, ref _forEach);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32929.385
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ecs.CSharp.Benchmark", "Ecs.CSharp.Benchmark\Ecs.CSharp.Benchmark.csproj", "{66637992-8C7F-44DB-BBE5-7AE008FC9BA9}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Solution Items", "_Solution Items", "{A2B996C4-02B6-4688-B4AB-DB24AF92BC1B}"
9 | ProjectSection(SolutionItems) = preProject
10 | .editorconfig = .editorconfig
11 | ..\.gitignore = ..\.gitignore
12 | NuGet.config = NuGet.config
13 | ..\Benchmark.bat = ..\Benchmark.bat
14 | ..\README.md = ..\README.md
15 | EndProjectSection
16 | EndProject
17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{FCF463F0-45FF-44D1-A5AF-8EDB5BB3E527}"
18 | ProjectSection(SolutionItems) = preProject
19 | ..\.github\workflows\ContinuousIntegration.yml = ..\.github\workflows\ContinuousIntegration.yml
20 | ..\.github\workflows\PullRequest.yml = ..\.github\workflows\PullRequest.yml
21 | EndProjectSection
22 | EndProject
23 | Global
24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
25 | Debug|Any CPU = Debug|Any CPU
26 | Release|Any CPU = Release|Any CPU
27 | EndGlobalSection
28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
29 | {66637992-8C7F-44DB-BBE5-7AE008FC9BA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {66637992-8C7F-44DB-BBE5-7AE008FC9BA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {66637992-8C7F-44DB-BBE5-7AE008FC9BA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {66637992-8C7F-44DB-BBE5-7AE008FC9BA9}.Release|Any CPU.Build.0 = Release|Any CPU
33 | EndGlobalSection
34 | GlobalSection(SolutionProperties) = preSolution
35 | HideSolutionNode = FALSE
36 | EndGlobalSection
37 | GlobalSection(NestedProjects) = preSolution
38 | {FCF463F0-45FF-44D1-A5AF-8EDB5BB3E527} = {A2B996C4-02B6-4688-B4AB-DB24AF92BC1B}
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {607C6B32-EA61-40B7-AEBF-1D6B5E765A3B}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/Arch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 | using Arch.Core;
4 | using Arch.Core.Utils;
5 | using Arch.System;
6 | using BenchmarkDotNet.Attributes;
7 | using Ecs.CSharp.Benchmark.Contexts;
8 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
9 |
10 | namespace Ecs.CSharp.Benchmark
11 | {
12 | public partial class SystemWithTwoComponents
13 | {
14 | private struct ForEach2 : IForEach
15 | {
16 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
17 | public void Update(ref Component1 t0, ref Component2 t1)
18 | {
19 | t0.Value += t1.Value;
20 | }
21 | }
22 |
23 | [Query]
24 | private static void ForEach(ref Component1 t0, Component2 t1)
25 | {
26 | t0.Value += t1.Value;
27 | }
28 |
29 | private sealed class ArchContext : ArchBaseContext
30 | {
31 | public ArchContext(int entityCount, int _)
32 | : base(_filter, entityCount)
33 | { }
34 | }
35 |
36 | private static readonly ComponentType[] _filter = [typeof(Component1), typeof(Component2)];
37 | private static readonly QueryDescription _queryDescription = new() { All = _filter };
38 |
39 | [Context]
40 | private readonly ArchContext _arch;
41 | private ForEach2 _forEach2;
42 |
43 | [BenchmarkCategory(Categories.Arch)]
44 | [Benchmark]
45 | public void Arch_MonoThread()
46 | {
47 | World world = _arch.World;
48 | world.InlineQuery(in _queryDescription, ref _forEach2);
49 | }
50 |
51 | [BenchmarkCategory(Categories.Arch)]
52 | [Benchmark]
53 | public void Arch_MonoThread_SourceGenerated()
54 | {
55 | ForEachQuery(_arch.World);
56 | }
57 |
58 | [BenchmarkCategory(Categories.Arch)]
59 | [Benchmark]
60 | public void Arch_MultiThread()
61 | {
62 | World world = _arch.World;
63 | world.InlineParallelQuery(in _queryDescription, ref _forEach2);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/SveltoECS.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using BenchmarkDotNet.Attributes;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 | using Svelto.DataStructures;
5 | using Svelto.ECS;
6 |
7 | namespace Ecs.CSharp.Benchmark
8 | {
9 | public partial class SystemWithOneComponent
10 | {
11 | private sealed class SveltoECSContext : SveltoECSBaseContext
12 | {
13 | public sealed class SveltoEngine : IQueryingEntitiesEngine
14 | {
15 | public EntitiesDB entitiesDB { get; set; }
16 |
17 | public void Ready()
18 | { }
19 |
20 | public void Update()
21 | {
22 | (NB entityViews, int count) = entitiesDB.QueryEntities(Group);
23 |
24 | for (int i = 0; i < count; i++)
25 | {
26 | ++entityViews[i].Value;
27 | }
28 | }
29 | }
30 |
31 | public sealed class PaddingEntity : IEntityDescriptor
32 | {
33 | public IComponentBuilder[] componentsToBuild => Array.Empty();
34 | }
35 |
36 | public sealed class Entity : GenericEntityDescriptor
37 | { }
38 |
39 | public SveltoEngine Engine { get; }
40 |
41 | public SveltoECSContext(int entityCount, int entityPadding)
42 | {
43 | Engine = new SveltoEngine();
44 | Root.AddEngine(Engine);
45 |
46 | uint id = 0;
47 | for (int i = 0; i < entityCount; ++i)
48 | {
49 | for (int j = 0; j < entityPadding; ++j)
50 | {
51 | Factory.BuildEntity(id++, Group);
52 | }
53 |
54 | Factory.BuildEntity(id++, Group);
55 | }
56 |
57 | Scheduler.SubmitEntities();
58 | }
59 | }
60 |
61 | [Context]
62 | private readonly SveltoECSContext _sveltoECS;
63 |
64 | [BenchmarkCategory(Categories.SveltoECS)]
65 | [Benchmark]
66 | public void SveltoECS() => _sveltoECS.Engine.Update();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/LeopotamEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.Ecs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class SystemWithTwoComponents
8 | {
9 | private sealed class LeopotamEcsContext : LeopotamEcsBaseContext
10 | {
11 | private sealed class MonoThreadRunSystem : IEcsRunSystem
12 | {
13 | private readonly EcsFilter _filter;
14 |
15 | public void Run()
16 | {
17 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++)
18 | {
19 | _filter.Get1(i).Value += _filter.Get2(i).Value;
20 | }
21 | }
22 | }
23 |
24 | public EcsSystems MonoThreadSystem { get; }
25 |
26 | public LeopotamEcsContext(int entityCount, int entityPadding)
27 | {
28 | MonoThreadSystem = new EcsSystems(World).Add(new MonoThreadRunSystem()).ProcessInjects();
29 |
30 | MonoThreadSystem.Init();
31 |
32 | for (int i = 0; i < entityCount; ++i)
33 | {
34 | for (int j = 0; j < entityPadding; ++j)
35 | {
36 | EcsEntity padding = World.NewEntity();
37 | switch (j % 2)
38 | {
39 | case 0:
40 | padding.Replace(new Component1());
41 | break;
42 |
43 | case 1:
44 | padding.Replace(new Component2());
45 | break;
46 | }
47 | }
48 |
49 | World.NewEntity()
50 | .Replace(new Component1())
51 | .Replace(new Component2 { Value = 1 });
52 | }
53 | }
54 | }
55 |
56 | [Context]
57 | private readonly LeopotamEcsContext _leopotamEcs;
58 |
59 | [BenchmarkCategory(Categories.LeopotamEcs)]
60 | [Benchmark]
61 | public void LeopotamEcs() => _leopotamEcs.MonoThreadSystem.Run();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/Arch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 | using Arch.Core;
4 | using Arch.Core.Utils;
5 | using Arch.System;
6 | using BenchmarkDotNet.Attributes;
7 | using Ecs.CSharp.Benchmark.Contexts;
8 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
9 |
10 | namespace Ecs.CSharp.Benchmark
11 | {
12 | public partial class SystemWithThreeComponents
13 | {
14 | private struct ForEach3 : IForEach
15 | {
16 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
17 | public void Update(ref Component1 t0, ref Component2 t1, ref Component3 t2)
18 | {
19 | t0.Value += t1.Value + t2.Value;
20 | }
21 | }
22 |
23 | [Query]
24 | private static void ForEach(ref Component1 t0, Component2 t1, Component3 t2)
25 | {
26 | t0.Value += t1.Value + t2.Value;
27 | }
28 |
29 | private sealed class ArchContext : ArchBaseContext
30 | {
31 | public ArchContext(int entityCount, int _)
32 | : base(_filter, entityCount)
33 | { }
34 | }
35 |
36 | private static readonly ComponentType[] _filter = [typeof(Component1), typeof(Component2), typeof(Component3)];
37 | private static readonly QueryDescription _queryDescription = new() { All = _filter };
38 |
39 | [Context]
40 | private readonly ArchContext _arch;
41 | private ForEach3 _forEach3;
42 |
43 | [BenchmarkCategory(Categories.Arch)]
44 | [Benchmark]
45 | public void Arch_MonoThread()
46 | {
47 | World world = _arch.World;
48 | world.InlineQuery(_queryDescription, ref _forEach3);
49 | }
50 |
51 | [BenchmarkCategory(Categories.Arch)]
52 | [Benchmark]
53 | public void Arch_MonoThread_SourceGenerated()
54 | {
55 | ForEachQuery(_arch.World);
56 | }
57 |
58 | [BenchmarkCategory(Categories.Arch)]
59 | [Benchmark]
60 | public void Arch_MultiThread()
61 | {
62 | World world = _arch.World;
63 | world.InlineParallelQuery(_queryDescription, ref _forEach3);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/RelEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using RelEcs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class SystemWithThreeComponents
8 | {
9 | private sealed class RelEcsContext : RelEcsBaseContext
10 | {
11 | private sealed class MonoThreadRunSystem : ISystem
12 | {
13 | public void Run(World world)
14 | {
15 | Query query = world.Query().Build();
16 | foreach ((Component1 c1, Component2 c2, Component3 c3) in query)
17 | {
18 | c1.Value += c2.Value + c3.Value;
19 | }
20 | }
21 | }
22 |
23 | public ISystem MonoThreadSystem { get; } = new MonoThreadRunSystem();
24 |
25 | public RelEcsContext(int entityCount, int entityPadding)
26 | {
27 | for (int i = 0; i < entityCount; ++i)
28 | {
29 | for (int j = 0; j < entityPadding; ++j)
30 | {
31 | EntityBuilder padding = World.Spawn();
32 | switch (j % 3)
33 | {
34 | case 0:
35 | padding.Add(new Component1());
36 | break;
37 |
38 | case 1:
39 | padding.Add(new Component2());
40 | break;
41 |
42 | case 2:
43 | padding.Add(new Component3());
44 | break;
45 | }
46 | }
47 |
48 | World.Spawn()
49 | .Add(new Component1())
50 | .Add(new Component2 { Value = 1 })
51 | .Add(new Component3 { Value = 1 });
52 | }
53 | }
54 | }
55 |
56 | [Context]
57 | private readonly RelEcsContext _relEcs;
58 |
59 | [BenchmarkCategory(Categories.RelEcs)]
60 | [Benchmark]
61 | public void RelEcs() => _relEcs.MonoThreadSystem.Run(_relEcs.World);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/RelEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using RelEcs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class SystemWithTwoComponentsMultipleComposition
8 | {
9 | private sealed class RelEcsContext : RelEcsBaseContext
10 | {
11 | private sealed record Padding1();
12 |
13 | private sealed record Padding2();
14 |
15 | private sealed record Padding3();
16 |
17 | private sealed record Padding4();
18 |
19 | private sealed class MonoThreadRunSystem : ISystem
20 | {
21 | public void Run(World world)
22 | {
23 | Query query = world.Query().Build();
24 | foreach ((Component1 c1, Component2 c2) in query)
25 | {
26 | c1.Value += c2.Value;
27 | }
28 | }
29 | }
30 |
31 | public ISystem MonoThreadSystem { get; } = new MonoThreadRunSystem();
32 |
33 | public RelEcsContext(int entityCount)
34 | {
35 | for (int i = 0; i < entityCount; ++i)
36 | {
37 | EntityBuilder entity = World.Spawn()
38 | .Add(new Component1())
39 | .Add(new Component2 { Value = 1 });
40 |
41 | switch (i % 4)
42 | {
43 | case 0:
44 | entity.Add();
45 | break;
46 |
47 | case 1:
48 | entity.Add();
49 | break;
50 |
51 | case 2:
52 | entity.Add();
53 | break;
54 |
55 | case 3:
56 | entity.Add();
57 | break;
58 | }
59 | }
60 | }
61 | }
62 |
63 | [Context] private readonly RelEcsContext _relEcs;
64 |
65 | [BenchmarkCategory(Categories.RelEcs)]
66 | [Benchmark]
67 | public void RelEcs() => _relEcs.MonoThreadSystem.Run(_relEcs.World);
68 | }
69 | }
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/TinyEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.TinyEcs_Components;
4 | using TinyEcs;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class SystemWithTwoComponentsMultipleComposition
9 | {
10 | [Context] private readonly TinyEcsContext _tinyEcs;
11 |
12 | private sealed class TinyEcsContext : TinyEcsBaseContext
13 | {
14 |
15 | private record struct Padding1();
16 | private record struct Padding2();
17 | private record struct Padding3();
18 | private record struct Padding4();
19 | public Query Query { get; }
20 |
21 |
22 | public TinyEcsContext(int entityCount) : base()
23 | {
24 | for (int i = 0; i < entityCount; ++i)
25 | {
26 | var entity = World.Entity();
27 | entity.Set();
28 | entity.Set(new Component2 { Value = 1 });
29 |
30 | switch (i % 4)
31 | {
32 | case 0:
33 | entity.Set();
34 | break;
35 |
36 | case 1:
37 | entity.Set();
38 | break;
39 |
40 | case 2:
41 | entity.Set();
42 | break;
43 |
44 | case 3:
45 | entity.Set();
46 | break;
47 | }
48 | }
49 |
50 | Query = World.QueryBuilder().With().With().Build();
51 | }
52 | }
53 |
54 | [BenchmarkCategory(Categories.TinyEcs)]
55 | [Benchmark]
56 | public void TinyEcs_Each()
57 | {
58 | _tinyEcs.Query.Each((ref Component1 c1, ref Component2 c2) => c1.Value += c2.Value);
59 | }
60 |
61 | [BenchmarkCategory(Categories.TinyEcs)]
62 | [Benchmark]
63 | public void TinyEcs_EachJob()
64 | {
65 | _tinyEcs.Query.EachJob((ref Component1 c1, ref Component2 c2) => c1.Value += c2.Value);
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/TinyEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.TinyEcs_Components;
4 | using TinyEcs;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class SystemWithThreeComponents
9 | {
10 | [Context] private readonly TinyEcsContext _tinyEcs;
11 |
12 | private sealed class TinyEcsContext : TinyEcsBaseContext
13 | {
14 | public Query Query { get; }
15 |
16 | public TinyEcsContext(int entityCount, int entityPadding) : base()
17 | {
18 | for (int i = 0; i < entityCount; ++i)
19 | {
20 | for (int j = 0; j < entityPadding; ++j)
21 | {
22 | var padding = World.Entity();
23 | switch (j % 3)
24 | {
25 | case 0:
26 | padding.Set(new Component1());
27 | break;
28 |
29 | case 1:
30 | padding.Set(new Component2());
31 | break;
32 |
33 | case 2:
34 | padding.Set(new Component3());
35 | break;
36 | }
37 | }
38 |
39 | World.Entity()
40 | .Set(new Component1())
41 | .Set(new Component2 { Value = 1 })
42 | .Set(new Component3 { Value = 1 });
43 |
44 | Query = World.QueryBuilder().With().With().With().Build();
45 | }
46 | }
47 | }
48 |
49 | [BenchmarkCategory(Categories.TinyEcs)]
50 | [Benchmark]
51 | public void TinyEcs_Each()
52 | {
53 | _tinyEcs.Query.Each((ref Component1 c1, ref Component2 c2, ref Component3 c3) => c1.Value += c2.Value + c3.Value);
54 | }
55 |
56 | [BenchmarkCategory(Categories.TinyEcs)]
57 | [Benchmark]
58 | public void TinyEcs_EachJob()
59 | {
60 | _tinyEcs.Query.EachJob((ref Component1 c1, ref Component2 c2, ref Component3 c3) => c1.Value += c2.Value + c3.Value);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/FlecsNet.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
4 | using Flecs.NET.Core;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class SystemWithTwoComponents
9 | {
10 | [Context]
11 | private readonly FlecsContext _flecs;
12 |
13 | private sealed class FlecsContext : FlecsNetBaseContext
14 | {
15 | public Query query;
16 |
17 | public FlecsContext(int entityCount, int entityPadding)
18 | {
19 | for (int i = 0; i < entityCount; ++i)
20 | {
21 | for (int j = 0; j < entityPadding; ++j)
22 | {
23 | Entity padding = World.Entity();
24 | switch (j % 2)
25 | {
26 | case 0:
27 | padding.Add();
28 | break;
29 |
30 | case 1:
31 | padding.Add();
32 | break;
33 | }
34 | }
35 |
36 | World.Entity().Add()
37 | .Set(new Component2
38 | {
39 | Value = 1
40 | });
41 | }
42 | query = World.QueryBuilder().With().With().Build();
43 | }
44 | }
45 |
46 | [BenchmarkCategory(Categories.FlecsNet)]
47 | [Benchmark]
48 | public void FlecsNet_Each()
49 | {
50 | _flecs.query.Each((ref Component1 c1, ref Component2 c2) =>
51 | {
52 | c1.Value += c2.Value;
53 | });
54 | }
55 |
56 | [BenchmarkCategory(Categories.FlecsNet)]
57 | [Benchmark]
58 | public void FlecsNet_Iter()
59 | {
60 | _flecs.query.Iter((Iter it, Column c1, Column c2) =>
61 | {
62 | foreach (int i in it)
63 | {
64 | c1[i].Value += c2[i].Value;
65 | }
66 | });
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/LeopotamEcsLite.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.EcsLite;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class SystemWithOneComponent
8 | {
9 | private sealed class LeopotamEcsLiteContext : LeopotamEcsLiteBaseContext
10 | {
11 | private sealed class MonoThreadRunSystem : IEcsInitSystem, IEcsRunSystem
12 | {
13 | private EcsFilter _filter;
14 | private EcsPool _components;
15 |
16 | public void Init(IEcsSystems systems)
17 | {
18 | EcsWorld world = systems.GetWorld();
19 |
20 | _filter = world.Filter().End();
21 | _components = world.GetPool();
22 | }
23 |
24 | public void Run(IEcsSystems systems)
25 | {
26 | int[] entities = _filter.GetRawEntities();
27 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++)
28 | {
29 | ++_components.Get(entities[i]).Value;
30 | }
31 | }
32 | }
33 |
34 | public IEcsSystems MonoThreadSystem { get; }
35 |
36 | public LeopotamEcsLiteContext(int entityCount, int entityPadding)
37 | {
38 | MonoThreadSystem = new EcsSystems(World).Add(new MonoThreadRunSystem());
39 |
40 | MonoThreadSystem.Init();
41 |
42 | EcsPool c1 = World.GetPool();
43 | EcsPool c2 = World.GetPool();
44 |
45 | for (int i = 0; i < entityCount; ++i)
46 | {
47 | for (int j = 0; j < entityPadding; ++j)
48 | {
49 | // LeopotamEcsLite does not support empty entities
50 | c2.Add(World.NewEntity());
51 | }
52 |
53 | int entity = World.NewEntity();
54 | c1.Add(entity);
55 | }
56 | }
57 | }
58 |
59 | [Context]
60 | private readonly LeopotamEcsLiteContext _leopotamEcsLite;
61 |
62 | [BenchmarkCategory(Categories.LeopotamEcsLite)]
63 | [Benchmark]
64 | public void LeopotamEcsLite() => _leopotamEcsLite.MonoThreadSystem.Run();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/HypEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using HypEcs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class SystemWithOneComponent
8 | {
9 | private sealed class HypEcsContext : HypEcsBaseContext
10 | {
11 | private sealed class MonoThreadRunSystem : ISystem
12 | {
13 | public void Run(World world)
14 | {
15 | Query query = world.Query().Build();
16 | query.Run((count, s1) =>
17 | {
18 | for (int i = 0; i < count; i++)
19 | {
20 | s1[i].Value++;
21 | }
22 | });
23 | }
24 | }
25 |
26 | private sealed class MultiThreadRunSystem : ISystem
27 | {
28 | public void Run(World world)
29 | {
30 | Query query = world.Query().Build();
31 | query.RunParallel((count, s1) =>
32 | {
33 | for (int i = 0; i < count; i++)
34 | {
35 | s1[i].Value++;
36 | }
37 | });
38 | }
39 | }
40 |
41 | public ISystem MonoThreadSystem { get; } = new MonoThreadRunSystem();
42 | public ISystem MultiThreadSystem { get; } = new MultiThreadRunSystem();
43 |
44 | public HypEcsContext(int entityCount, int entityPadding)
45 | {
46 | for (int i = 0; i < entityCount; ++i)
47 | {
48 | for (int j = 0; j < entityPadding; ++j)
49 | {
50 | World.Spawn();
51 | }
52 |
53 | World
54 | .Spawn()
55 | .Add(new Component1());
56 | }
57 | }
58 | }
59 |
60 | [Context] private readonly HypEcsContext _hypEcs;
61 |
62 | [BenchmarkCategory(Categories.HypEcs)]
63 | [Benchmark]
64 | public void HypEcs_MonoThread() => _hypEcs.MonoThreadSystem.Run(_hypEcs.World);
65 |
66 | [BenchmarkCategory(Categories.HypEcs)]
67 | [Benchmark]
68 | public void HypEcs_MultiThread() => _hypEcs.MultiThreadSystem.Run(_hypEcs.World);
69 | }
70 | }
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/LeopotamEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.Ecs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class SystemWithThreeComponents
8 | {
9 | private sealed class LeopotamEcsContext : LeopotamEcsBaseContext
10 | {
11 | private sealed class MonoThreadRunSystem : IEcsRunSystem
12 | {
13 | private readonly EcsFilter _filter;
14 |
15 | public void Run()
16 | {
17 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++)
18 | {
19 | _filter.Get1(i).Value += _filter.Get2(i).Value + _filter.Get3(i).Value;
20 | }
21 | }
22 | }
23 |
24 | public EcsSystems MonoThreadSystem { get; }
25 |
26 | public LeopotamEcsContext(int entityCount, int entityPadding)
27 | {
28 | MonoThreadSystem = new EcsSystems(World).Add(new MonoThreadRunSystem()).ProcessInjects();
29 |
30 | MonoThreadSystem.Init();
31 |
32 | for (int i = 0; i < entityCount; ++i)
33 | {
34 | for (int j = 0; j < entityPadding; ++j)
35 | {
36 | EcsEntity padding = World.NewEntity();
37 | switch (j % 3)
38 | {
39 | case 0:
40 | padding.Replace(new Component1());
41 | break;
42 |
43 | case 1:
44 | padding.Replace(new Component2());
45 | break;
46 |
47 | case 2:
48 | padding.Replace(new Component3());
49 | break;
50 | }
51 | }
52 |
53 | World.NewEntity()
54 | .Replace(new Component1())
55 | .Replace(new Component2 { Value = 1 })
56 | .Replace(new Component3 { Value = 1 });
57 | }
58 | }
59 | }
60 |
61 | [Context]
62 | private readonly LeopotamEcsContext _leopotamEcs;
63 |
64 | [BenchmarkCategory(Categories.LeopotamEcs)]
65 | [Benchmark]
66 | public void LeopotamEcs() => _leopotamEcs.MonoThreadSystem.Run();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/Frent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Runtime.Intrinsics;
4 | using BenchmarkDotNet.Attributes;
5 | using Ecs.CSharp.Benchmark.Contexts;
6 | using Frent;
7 | using Frent.Systems;
8 | using static Ecs.CSharp.Benchmark.Contexts.FrentBaseContext;
9 |
10 | namespace Ecs.CSharp.Benchmark
11 | {
12 | public partial class SystemWithOneComponent
13 | {
14 | [Context]
15 | private readonly FrentContext _frent;
16 |
17 | private sealed class FrentContext : FrentBaseContext
18 | {
19 | public FrentContext(int entityCount, int entityPadding)
20 | {
21 | for (int i = 0; i < entityCount; i++)
22 | {
23 | World.Create(default);
24 | for (int j = 0; j < entityPadding; j++)
25 | {
26 | World.Create();
27 | }
28 | }
29 |
30 | Query = World.Query>();
31 | }
32 |
33 | public Query Query;
34 | }
35 |
36 | internal struct Increment : IAction
37 | {
38 | public void Run(ref Component1 t0)
39 | {
40 | t0.Value++;
41 | }
42 | }
43 |
44 | [BenchmarkCategory(Categories.Frent)]
45 | [Benchmark]
46 | public void Frent_QueryInline()
47 | {
48 | _frent.Query.Inline(default);
49 | }
50 |
51 | [BenchmarkCategory(Categories.Frent)]
52 | [Benchmark]
53 | public void Frent_QueryDelegate()
54 | {
55 | _frent.Query.Delegate((ref Component1 c) => c.Value++);
56 | }
57 |
58 | [BenchmarkCategory(Categories.Frent)]
59 | [Benchmark]
60 | public void Frent_Simd()
61 | {
62 | Vector256 sum = Vector256.Create(1);
63 | foreach (ChunkTuple chunk in _frent.Query.EnumerateChunks())
64 | {
65 | int len = chunk.Span.Length - (chunk.Span.Length & 7);
66 | Span> ints = MemoryMarshal.Cast>(chunk.Span.Slice(0, len));
67 | for (int i = 0; i < ints.Length; i++)
68 | {
69 | ints[i] += sum;
70 | }
71 |
72 | for (int i = len; i < chunk.Span.Length; i++)
73 | {
74 | chunk.Span[i].Value++;
75 | }
76 | }
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/Fennecs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 | using BenchmarkDotNet.Attributes;
4 | using Ecs.CSharp.Benchmark.Contexts;
5 | using Ecs.CSharp.Benchmark.Contexts.Fennecs_Components;
6 | using fennecs;
7 |
8 | namespace Ecs.CSharp.Benchmark
9 | {
10 | public partial class SystemWithTwoComponents
11 | {
12 | [Context] private readonly FennecsContext _fennecs;
13 |
14 | private sealed class FennecsContext : FennecsBaseContext
15 | {
16 | public Query query;
17 |
18 | public FennecsContext(int entityCount, int entityPadding)
19 | {
20 | query = World.Query().Build();
21 | for (int i = 0; i < entityCount; ++i)
22 | {
23 | for (int j = 0; j < entityPadding; ++j)
24 | {
25 | Entity padding = World.Spawn();
26 | switch (j % 2)
27 | {
28 | case 0:
29 | padding.Add();
30 | break;
31 |
32 | case 1:
33 | padding.Add();
34 | break;
35 | }
36 | }
37 |
38 | World.Spawn().Add().Add(new Component2 { Value = 1 });
39 | }
40 | }
41 | }
42 |
43 | [BenchmarkCategory(Categories.Fennecs)]
44 | [Benchmark]
45 | public void Fennecs_ForEach()
46 | {
47 | _fennecs.query.For((ref Component1 c1, ref Component2 c2) => c1.Value += c2.Value);
48 | }
49 |
50 | [BenchmarkCategory(Categories.Fennecs)]
51 | [Benchmark]
52 | public void Fennecs_Job()
53 | {
54 | _fennecs.query.Job(delegate(ref Component1 c1, ref Component2 c2) { c1.Value += c2.Value; }, 1024);
55 | }
56 |
57 | [BenchmarkCategory(Categories.Fennecs)]
58 | [Benchmark]
59 | public void Fennecs_Raw()
60 | {
61 | _fennecs.query.Raw(delegate(Memory c1v, Memory c2v)
62 | {
63 | var c1vs = c1v.Span;
64 | var c2vs = c2v.Span;
65 | for (int i = 0; i < c1vs.Length; ++i)
66 | {
67 | ref Component1 c1 = ref c1vs[i];
68 | c1.Value += c2vs[i].Value;
69 | }
70 | });
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/FlecsNet.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
4 | using Flecs.NET.Core;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class SystemWithTwoComponentsMultipleComposition
9 | {
10 | [Context]
11 | private readonly FlecsContext _flecs;
12 |
13 |
14 | private sealed class FlecsContext : FlecsNetBaseContext
15 | {
16 |
17 | private record struct Padding1();
18 |
19 | private record struct Padding2();
20 |
21 | private record struct Padding3();
22 |
23 | private record struct Padding4();
24 |
25 | public Query query;
26 |
27 | public FlecsContext(int entityCount)
28 | {
29 | for (int i = 0; i < entityCount; ++i)
30 | {
31 | Entity entity = World.Entity().Add().Set(new Component2 { Value = 1 });
32 | switch (i % 4)
33 | {
34 | case 0:
35 | entity.Add();
36 | break;
37 | case 1:
38 | entity.Add();
39 | break;
40 | case 2:
41 | entity.Add();
42 | break;
43 | case 3:
44 | entity.Add();
45 | break;
46 | }
47 | }
48 | query = World.QueryBuilder().With().With().Build();
49 | }
50 | }
51 |
52 | [BenchmarkCategory(Categories.FlecsNet)]
53 | [Benchmark]
54 | public void FlecsNet_Each()
55 | {
56 | _flecs.query.Each((ref Component1 c1, ref Component2 c2) =>
57 | {
58 | c1.Value += c2.Value;
59 | });
60 | }
61 |
62 | [BenchmarkCategory(Categories.FlecsNet)]
63 | [Benchmark]
64 | public void FlecsNet_Iter()
65 | {
66 | _flecs.query.Iter((Iter it, Column c1, Column c2) =>
67 | {
68 | foreach (int i in it)
69 | {
70 | c1[i].Value += c2[i].Value;
71 | }
72 | });
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/MonoGameExtended.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Microsoft.Xna.Framework;
4 | using MonoGame.Extended.Entities;
5 | using MonoGame.Extended.Entities.Systems;
6 |
7 | namespace Ecs.CSharp.Benchmark
8 | {
9 | public partial class SystemWithOneComponent
10 | {
11 | private sealed class MonoGameExtendedContext : MonoGameExtendedBaseContext
12 | {
13 | public sealed class UpdateSystem : EntityUpdateSystem
14 | {
15 | private ComponentMapper _components;
16 |
17 | public UpdateSystem()
18 | : base(Aspect.All(typeof(Component1)))
19 | { }
20 |
21 | public override void Initialize(IComponentMapperService mapperService)
22 | {
23 | _components = mapperService.GetMapper();
24 | }
25 |
26 | public override void Update(GameTime gameTime)
27 | {
28 | foreach (int entityId in ActiveEntities)
29 | {
30 | ++_components.Get(entityId).Value;
31 | }
32 | }
33 | }
34 |
35 | private readonly UpdateSystem _system;
36 |
37 | public new World World { get; }
38 |
39 | public GameTime Time { get; }
40 |
41 | public MonoGameExtendedContext(int entityCount, int entityPadding)
42 | {
43 | _system = new UpdateSystem();
44 | World = new WorldBuilder().AddSystem(_system).Build();
45 | Time = new GameTime();
46 |
47 | for (int i = 0; i < entityCount; ++i)
48 | {
49 | for (int j = 0; j < entityPadding; ++j)
50 | {
51 | World.CreateEntity();
52 | }
53 |
54 | Entity entity = World.CreateEntity();
55 | entity.Attach(new Component1());
56 | }
57 | }
58 |
59 | public override void Dispose()
60 | {
61 | World.Dispose();
62 | _system.Dispose();
63 |
64 | base.Dispose();
65 | }
66 | }
67 |
68 | [Context]
69 | private readonly MonoGameExtendedContext _monoGameExtended;
70 |
71 | [BenchmarkCategory(Categories.MonoGameExtended)]
72 | [Benchmark]
73 | public void MonoGameExtended() => _monoGameExtended.World.Update(_monoGameExtended.Time);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/LeopotamEcs.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Leopotam.Ecs;
4 |
5 | namespace Ecs.CSharp.Benchmark
6 | {
7 | public partial class SystemWithTwoComponentsMultipleComposition
8 | {
9 | private sealed class LeopotamEcsContext : LeopotamEcsBaseContext
10 | {
11 | private record struct Padding1();
12 |
13 | private record struct Padding2();
14 |
15 | private record struct Padding3();
16 |
17 | private record struct Padding4();
18 |
19 | private sealed class MonoThreadRunSystem : IEcsRunSystem
20 | {
21 | private readonly EcsFilter _filter;
22 |
23 | public void Run()
24 | {
25 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++)
26 | {
27 | _filter.Get1(i).Value += _filter.Get2(i).Value;
28 | }
29 | }
30 | }
31 |
32 | public EcsSystems MonoThreadSystem { get; }
33 |
34 | public LeopotamEcsContext(int entityCount)
35 | {
36 | MonoThreadSystem = new EcsSystems(World).Add(new MonoThreadRunSystem()).ProcessInjects();
37 |
38 | MonoThreadSystem.Init();
39 |
40 | for (int i = 0; i < entityCount; ++i)
41 | {
42 | EcsEntity entity = World
43 | .NewEntity()
44 | .Replace(new Component1())
45 | .Replace(new Component2 { Value = 1 });
46 |
47 | switch (i % 4)
48 | {
49 | case 0:
50 | entity.Replace(new Padding1());
51 | break;
52 |
53 | case 1:
54 | entity.Replace(new Padding2());
55 | break;
56 |
57 | case 2:
58 | entity.Replace(new Padding3());
59 | break;
60 |
61 | case 3:
62 | entity.Replace(new Padding4());
63 | break;
64 | }
65 | }
66 | }
67 | }
68 |
69 | [Context]
70 | private readonly LeopotamEcsContext _leopotamEcs;
71 |
72 | [BenchmarkCategory(Categories.LeopotamEcs)]
73 | [Benchmark]
74 | public void LeopotamEcs() => _leopotamEcs.MonoThreadSystem.Run();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/Frent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Runtime.Intrinsics;
4 | using BenchmarkDotNet.Attributes;
5 | using Ecs.CSharp.Benchmark.Contexts;
6 | using Frent;
7 | using Frent.Systems;
8 | using static Ecs.CSharp.Benchmark.Contexts.FrentBaseContext;
9 |
10 | namespace Ecs.CSharp.Benchmark
11 | {
12 | public partial class SystemWithTwoComponents
13 | {
14 | [Context]
15 | private readonly FrentContext _frent;
16 |
17 | internal sealed class FrentContext : FrentBaseContext
18 | {
19 | public FrentContext(int entityCount, int padding)
20 | {
21 | for (int i = 0; i < entityCount; i++)
22 | {
23 | World.Create(default, new() { Value = 1 });
24 | for (int j = 0; j < padding; j++)
25 | {
26 | World.Create();
27 | }
28 | }
29 |
30 | Query = World.Query, With>();
31 | }
32 |
33 | public Query Query;
34 | }
35 |
36 | internal struct Sum : IAction
37 | {
38 | public void Run(ref Component1 t0, ref Component2 t1)
39 | {
40 | t0.Value += t1.Value;
41 | }
42 | }
43 |
44 | [BenchmarkCategory(Categories.Frent)]
45 | [Benchmark]
46 | public void Frent_QueryInline()
47 | {
48 | _frent.Query.Inline(default);
49 | }
50 |
51 | [BenchmarkCategory(Categories.Frent)]
52 | [Benchmark]
53 | public void Frent_QueryDelegate()
54 | {
55 | _frent.Query.Delegate((ref Component1 c1, ref Component2 c2) => c1.Value += c2.Value);
56 | }
57 |
58 | [BenchmarkCategory(Categories.Frent)]
59 | [Benchmark]
60 | public void Frent_Simd()
61 | {
62 | foreach ((var s1, var s2) in _frent.Query.EnumerateChunks())
63 | {
64 | int len = s1.Length - (s1.Length & 7);
65 |
66 | Span> ints = MemoryMarshal.Cast>(s1.Slice(0, len));
67 | Span> a = MemoryMarshal.Cast>(s2.Slice(0, len))[..ints.Length];
68 |
69 | for (int i = 0; i < ints.Length; i++)
70 | ints[i] += a[i];
71 |
72 | for (int i = len; i < s1.Length; i++)
73 | s1[i].Value += s2[i].Value;
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/FlecsNet.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Ecs.CSharp.Benchmark.Contexts;
3 | using Ecs.CSharp.Benchmark.Contexts.Arch_Components;
4 | using Flecs.NET.Core;
5 |
6 | namespace Ecs.CSharp.Benchmark
7 | {
8 | public partial class SystemWithThreeComponents
9 | {
10 | [Context]
11 | private readonly FlecsContext _flecs;
12 |
13 | private sealed class FlecsContext : FlecsNetBaseContext
14 | {
15 | public Query query;
16 |
17 | public FlecsContext(int entityCount, int entityPadding)
18 | {
19 | for (int i = 0; i < entityCount; ++i)
20 | {
21 | for (int j = 0; j < entityPadding; ++j)
22 | {
23 | Entity padding = World.Entity();
24 | switch (j % 3)
25 | {
26 | case 0:
27 | padding.Add();
28 | break;
29 |
30 | case 1:
31 | padding.Add();
32 | break;
33 |
34 | case 2:
35 | padding.Add();
36 | break;
37 | }
38 | }
39 |
40 | World.Entity().Add()
41 | .Set(new Component2
42 | {
43 | Value = 1
44 | })
45 | .Set(new Component3
46 | {
47 | Value = 1
48 | });
49 | }
50 | query = World.QueryBuilder().With().With().With().Build();
51 | }
52 | }
53 |
54 | [BenchmarkCategory(Categories.FlecsNet)]
55 | [Benchmark]
56 | public void FlecsNet_Each()
57 | {
58 | _flecs.query.Each((ref Component1 c1, ref Component2 c2, ref Component3 c3) =>
59 | {
60 | c1.Value += c2.Value + c3.Value;
61 | });
62 | }
63 |
64 | [BenchmarkCategory(Categories.FlecsNet)]
65 | [Benchmark]
66 | public void FlecsNet_Iter()
67 | {
68 | _flecs.query.Iter((Iter it, Column c1, Column c2, Column c3) =>
69 | {
70 | foreach (int i in it)
71 | {
72 | c1[i].Value += c2[i].Value + c3[i].Value;
73 | }
74 | });
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/SveltoECS.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using BenchmarkDotNet.Attributes;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 | using Svelto.DataStructures;
5 | using Svelto.ECS;
6 |
7 | namespace Ecs.CSharp.Benchmark
8 | {
9 | public partial class SystemWithTwoComponents
10 | {
11 | private sealed class SveltoECSContext : SveltoECSBaseContext
12 | {
13 | public sealed class SveltoEngine : IQueryingEntitiesEngine
14 | {
15 | public EntitiesDB entitiesDB { get; set; }
16 |
17 | public void Ready()
18 | { }
19 |
20 | public void Update()
21 | {
22 | (NB c1, NB c2, int count) = entitiesDB.QueryEntities(Group);
23 |
24 | for (int i = 0; i < count; i++)
25 | {
26 | c1[i].Value += c2[i].Value;
27 | }
28 | }
29 | }
30 |
31 | public sealed class Padding1Entity : GenericEntityDescriptor
32 | { }
33 |
34 | public sealed class Padding2Entity : GenericEntityDescriptor
35 | { }
36 |
37 | public sealed class Entity : GenericEntityDescriptor
38 | { }
39 |
40 | public SveltoEngine Engine { get; }
41 |
42 | public SveltoECSContext(int entityCount, int entityPadding)
43 | {
44 | Engine = new SveltoEngine();
45 | Root.AddEngine(Engine);
46 |
47 | uint id = 0;
48 | for (int i = 0; i < entityCount; ++i)
49 | {
50 | for (int j = 0; j < entityPadding; ++j)
51 | {
52 | switch (j % 2)
53 | {
54 | case 0:
55 | Factory.BuildEntity(id++, Group);
56 | break;
57 |
58 | case 1:
59 | Factory.BuildEntity(id++, Group);
60 | break;
61 | }
62 | }
63 |
64 | EntityInitializer entity = Factory.BuildEntity(id++, Group);
65 | entity.GetOrAdd() = new Component2 { Value = 1 };
66 | }
67 |
68 | Scheduler.SubmitEntities();
69 | }
70 | }
71 |
72 | [Context]
73 | private readonly SveltoECSContext _sveltoECS;
74 |
75 | [BenchmarkCategory(Categories.SveltoECS)]
76 | [Benchmark]
77 | public void SveltoECS() => _sveltoECS.Engine.Update();
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/DefaultEcs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using BenchmarkDotNet.Attributes;
3 | using DefaultEcs;
4 | using DefaultEcs.System;
5 | using DefaultEcs.Threading;
6 | using Ecs.CSharp.Benchmark.Contexts;
7 |
8 | namespace Ecs.CSharp.Benchmark
9 | {
10 | public partial class SystemWithTwoComponents
11 | {
12 | private sealed partial class DefaultEcsContext : DefaultEcsBaseContext
13 | {
14 | private sealed partial class EntitySetSystem : AEntitySetSystem
15 | {
16 | [Update]
17 | private static void Update(ref Component1 c1, in Component2 c2)
18 | {
19 | c1.Value += c2.Value;
20 | }
21 | }
22 |
23 | public IParallelRunner Runner { get; }
24 |
25 | public ISystem MonoThreadEntitySetSystem { get; }
26 |
27 | public ISystem MultiThreadEntitySetSystem { get; }
28 |
29 | public DefaultEcsContext(int entityCount, int entityPadding)
30 | {
31 | Runner = new DefaultParallelRunner(Environment.ProcessorCount);
32 | MonoThreadEntitySetSystem = new EntitySetSystem(World);
33 | MultiThreadEntitySetSystem = new EntitySetSystem(World, Runner);
34 |
35 | for (int i = 0; i < entityCount; ++i)
36 | {
37 | for (int j = 0; j < entityPadding; ++j)
38 | {
39 | Entity padding = World.CreateEntity();
40 | switch (j % 2)
41 | {
42 | case 0:
43 | padding.Set();
44 | break;
45 |
46 | case 1:
47 | padding.Set();
48 | break;
49 | }
50 | }
51 |
52 | Entity entity = World.CreateEntity();
53 | entity.Set();
54 | entity.Set(new Component2 { Value = 1 });
55 | }
56 | }
57 |
58 | public override void Dispose()
59 | {
60 | base.Dispose();
61 |
62 | Runner.Dispose();
63 | }
64 | }
65 |
66 | [Context]
67 | private readonly DefaultEcsContext _defaultEcs;
68 |
69 | [BenchmarkCategory(Categories.DefaultEcs)]
70 | [Benchmark]
71 | public void DefaultEcs_MonoThread() => _defaultEcs.MonoThreadEntitySetSystem.Update(0);
72 |
73 | [BenchmarkCategory(Categories.DefaultEcs)]
74 | [Benchmark]
75 | public void DefaultEcs_MultiThread() => _defaultEcs.MultiThreadEntitySetSystem.Update(0);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/Frent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Runtime.Intrinsics;
4 | using BenchmarkDotNet.Attributes;
5 | using Ecs.CSharp.Benchmark.Contexts;
6 | using Frent;
7 | using Frent.Systems;
8 | using static Ecs.CSharp.Benchmark.Contexts.FrentBaseContext;
9 |
10 | namespace Ecs.CSharp.Benchmark
11 | {
12 | public partial class SystemWithThreeComponents
13 | {
14 | [Context]
15 | private readonly FrentContext _frent;
16 |
17 | private sealed class FrentContext : FrentBaseContext
18 | {
19 | public FrentContext(int entityCount, int _)
20 | {
21 | for (int i = 0; i < entityCount; i++)
22 | {
23 | World.Create(default, new() { Value = 1 }, new() { Value = 1 });
24 | }
25 |
26 | Query = World.Query, With, With>();
27 | }
28 |
29 | public Query Query;
30 | }
31 |
32 | internal struct Sum : IAction
33 | {
34 | public void Run(ref Component1 t0, ref Component2 t1, ref Component3 t2)
35 | {
36 | t0.Value += t1.Value + t2.Value;
37 | }
38 | }
39 |
40 | [BenchmarkCategory(Categories.Frent)]
41 | [Benchmark]
42 | public void Frent_QueryInline()
43 | {
44 | _frent.Query.Inline(default);
45 | }
46 |
47 | [BenchmarkCategory(Categories.Frent)]
48 | [Benchmark]
49 | public void Frent_QueryDelegate()
50 | {
51 | _frent.Query.Delegate((ref Component1 c1, ref Component2 c2, ref Component1 c3) => c1.Value += c2.Value + c3.Value);
52 | }
53 |
54 | [BenchmarkCategory(Categories.Frent)]
55 | [Benchmark]
56 | public void Frent_Simd()
57 | {
58 | foreach ((var s1, var s2, var s3) in _frent.Query.EnumerateChunks())
59 | {
60 | int len = s1.Length - (s1.Length & 7);
61 |
62 | Span> ints = MemoryMarshal.Cast>(s1.Slice(0, len));
63 | Span> a = MemoryMarshal.Cast>(s2.Slice(0, len))[..ints.Length];
64 | Span> b = MemoryMarshal.Cast>(s3.Slice(0, len))[..ints.Length];
65 |
66 | for (int i = 0; i < ints.Length; i++)
67 | ints[i] += a[i] + b[i];
68 |
69 | for (int i = len; i < s1.Length; i++)
70 | s1[i].Value += s2[i].Value + s3[i].Value;
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithOneComponent/FrifloEngineEcs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Intrinsics;
3 | using BenchmarkDotNet.Attributes;
4 | using Ecs.CSharp.Benchmark.Contexts;
5 | using Ecs.CSharp.Benchmark.Contexts.FrifloEngine_Components;
6 | using Friflo.Engine.ECS;
7 |
8 | namespace Ecs.CSharp.Benchmark
9 | {
10 | public partial class SystemWithOneComponent
11 | {
12 | internal sealed class FrifloEngineEcsContext : FrifloEngineEcsBaseContext
13 | {
14 | public FrifloEngineEcsContext(int entityCount, int padding)
15 | : base(entityCount, padding, ComponentTypes.Get())
16 | { }
17 |
18 | internal static void ForEach(Chunk component1, ChunkEntities entities)
19 | {
20 | foreach (ref Component1 component in component1.Span)
21 | {
22 | ++component.Value;
23 | }
24 | }
25 | }
26 |
27 | [Context]
28 | private readonly FrifloEngineEcsContext _frifloEngineEcs;
29 |
30 | [BenchmarkCategory(Categories.FrifloEngineEcs)]
31 | [Benchmark]
32 | public void FrifloEngineEcs_MonoThread()
33 | {
34 | foreach ((Chunk component1, ChunkEntities _) in _frifloEngineEcs.queryOne.Chunks)
35 | {
36 | foreach (ref Component1 component in component1.Span)
37 | {
38 | ++component.Value;
39 | }
40 | }
41 | }
42 |
43 | [BenchmarkCategory(Categories.FrifloEngineEcs)]
44 | [Benchmark]
45 | public void FrifloEngineEcs_MultiThread()
46 | {
47 | _frifloEngineEcs.jobOne.RunParallel();
48 | }
49 |
50 | [BenchmarkCategory(Categories.FrifloEngineEcs)]
51 | [Benchmark]
52 | public void FrifloEngineEcs_SIMD_MonoThread()
53 | {
54 | Vector256 add = Vector256.Create(1); // create int[8] vector - all values = 1
55 |
56 | foreach ((Chunk component1, ChunkEntities _) in _frifloEngineEcs.queryOne.Chunks)
57 | {
58 | Span component1Span = component1.AsSpan256(); // Length - multiple of 8
59 | int step = component1.StepSpan256; // step = 8
60 | for (int n = 0; n < component1Span.Length; n += step)
61 | {
62 | Span slice = component1Span.Slice(n, step);
63 | Vector256 value = Vector256.Create(slice);
64 | Vector256 result = Vector256.Add(value, add); // execute 8 add instructions at once
65 | result.CopyTo(slice);
66 | }
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/Fennecs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using BenchmarkDotNet.Attributes;
3 | using Ecs.CSharp.Benchmark.Contexts;
4 | using Ecs.CSharp.Benchmark.Contexts.Fennecs_Components;
5 | using fennecs;
6 |
7 | namespace Ecs.CSharp.Benchmark
8 | {
9 | public partial class SystemWithTwoComponentsMultipleComposition
10 | {
11 | [Context] private readonly FennecsContext _fennecs;
12 |
13 | private sealed class FennecsContext : FennecsBaseContext
14 | {
15 | private record struct Padding1();
16 |
17 | private record struct Padding2();
18 |
19 | private record struct Padding3();
20 |
21 | private record struct Padding4();
22 |
23 | public Query query;
24 |
25 | public FennecsContext(int entityCount)
26 | {
27 | query = World.Query().Build();
28 | for (int i = 0; i < entityCount; ++i)
29 | {
30 | Entity entity = World.Spawn().Add().Add(new Component2 { Value = 1 });
31 | switch (i % 4)
32 | {
33 | case 0:
34 | entity.Add();
35 | break;
36 | case 1:
37 | entity.Add();
38 | break;
39 | case 2:
40 | entity.Add();
41 | break;
42 | case 3:
43 | entity.Add();
44 | break;
45 | }
46 | }
47 | }
48 | }
49 |
50 | [BenchmarkCategory(Categories.Fennecs)]
51 | [Benchmark]
52 | public void Fennecs_ForEach()
53 | {
54 | _fennecs.query.For((ref Component1 c1, ref Component2 c2) => c1.Value += c2.Value);
55 | }
56 |
57 | [BenchmarkCategory(Categories.Fennecs)]
58 | [Benchmark]
59 | public void Fennecs_Job()
60 | {
61 | _fennecs.query.Job(delegate(ref Component1 c1, ref Component2 c2) { c1.Value += c2.Value; }, 1024);
62 | }
63 |
64 | [BenchmarkCategory(Categories.Fennecs)]
65 | [Benchmark]
66 | public void Fennecs_Raw()
67 | {
68 | _fennecs.query.Raw(delegate(Memory c1v, Memory c2v)
69 | {
70 | var c1vs = c1v.Span;
71 | var c2vs = c2v.Span;
72 | for (int i = 0; i < c1vs.Length; ++i)
73 | {
74 | ref Component1 c1 = ref c1vs[i];
75 | c1.Value += c2vs[i].Value;
76 | }
77 | });
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/Frent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Runtime.Intrinsics;
4 | using BenchmarkDotNet.Attributes;
5 | using Ecs.CSharp.Benchmark.Contexts;
6 | using Frent;
7 | using Frent.Systems;
8 | using static Ecs.CSharp.Benchmark.Contexts.FrentBaseContext;
9 |
10 | namespace Ecs.CSharp.Benchmark
11 | {
12 | public partial class SystemWithTwoComponentsMultipleComposition
13 | {
14 | [Context]
15 | private readonly FrentContext _frent;
16 | internal sealed class FrentContext : FrentBaseContext
17 | {
18 | public FrentContext(int entityCount)
19 | {
20 | for (int i = 0; i < entityCount; i++)
21 | {
22 | Entity e = (entityCount % 4) switch
23 | {
24 | 0 => World.Create(default, new() { Value = 1 }, default),
25 | 1 => World.Create(default, new() { Value = 1 }, default),
26 | 2 => World.Create(default, new() { Value = 1 }, default),
27 | _ => World.Create(default, new() { Value = 1 }, default),
28 | };
29 | }
30 |
31 | Query = World.Query, With