├── .github ├── FUNDING.yml └── workflows │ ├── ContinuousIntegration.yml │ └── PullRequest.yml ├── .gitignore ├── Benchmark.bat ├── LICENSE.md ├── README.md ├── results ├── Ecs.CSharp.Benchmark.CreateEntityWithOneComponent-report-github.md ├── Ecs.CSharp.Benchmark.CreateEntityWithThreeComponents-report-github.md ├── Ecs.CSharp.Benchmark.CreateEntityWithTwoComponents-report-github.md ├── Ecs.CSharp.Benchmark.SystemWithOneComponent-report-github.md ├── Ecs.CSharp.Benchmark.SystemWithThreeComponents-report-github.md ├── Ecs.CSharp.Benchmark.SystemWithTwoComponents-report-github.md └── Ecs.CSharp.Benchmark.SystemWithTwoComponentsMultipleComposition-report-github.md └── source ├── .editorconfig ├── Ecs.CSharp.Benchmark.sln ├── Ecs.CSharp.Benchmark ├── BenchmarkOperations.cs ├── Categories.cs ├── ContextAttribute.cs ├── Contexts │ ├── ArchBaseContext.cs │ ├── DefaultEcsBaseContext.cs │ ├── FennecsBaseContext.cs │ ├── FlecsNetBaseContext.cs │ ├── FrentBaseContext.cs │ ├── FrifloEngineEcsContext.cs │ ├── HypEcsBaseContext.cs │ ├── LeopotamEcsBaseContext.cs │ ├── LeopotamEcsLiteBaseContext.cs │ ├── MonoGameExtendedBaseContext.cs │ ├── MorpehBaseContext.cs │ ├── MyriadBaseContext.cs │ ├── RelEcsBaseContext.cs │ ├── SveltoECSBaseContext.cs │ └── TinyEcsBaseContext.cs ├── CreateEntityWithOneComponent │ ├── Arch.cs │ ├── DefaultEcs.cs │ ├── Fennecs.cs │ ├── FlecsNet.cs │ ├── Frent.cs │ ├── FrifloEngineEcs.cs │ ├── HypEcs.cs │ ├── LeopotamEcs.cs │ ├── LeopotamEcsLite.cs │ ├── MonoGameExtended.cs │ ├── Morpeh.cs │ ├── Myriad.cs │ ├── RelEcs.cs │ ├── SveltoECS.cs │ ├── TinyEcs.cs │ └── _CreateEntityWithOneComponent.cs ├── CreateEntityWithThreeComponents │ ├── Arch.cs │ ├── DefaultEcs.cs │ ├── Fennecs.cs │ ├── FlecsNet.cs │ ├── Frent.cs │ ├── FrifloEngineEcs.cs │ ├── HypEcs.cs │ ├── LeopotamEcs.cs │ ├── LeopotamEcsLite.cs │ ├── MonoGameExtended.cs │ ├── Morpeh.cs │ ├── Myriad.cs │ ├── RelEcs.cs │ ├── SveltoECS.cs │ ├── TinyEcs.cs │ └── _CreateEntityWithThreeComponents.cs ├── CreateEntityWithTwoComponents │ ├── Arch.cs │ ├── DefaultEcs.cs │ ├── Fennecs.cs │ ├── FlecsNet.cs │ ├── Frent.cs │ ├── FrifloEngineEcs.cs │ ├── HypEcs.cs │ ├── LeopotamEcs.cs │ ├── LeopotamEcsLite.cs │ ├── MonoGameExtended.cs │ ├── Morpeh.cs │ ├── Myriad.cs │ ├── RelEcs.cs │ ├── SveltoECS.cs │ ├── TinyEcs.cs │ └── _CreateEntityWithTwoComponents.cs ├── Ecs.CSharp.Benchmark.csproj ├── Program.cs ├── SystemWithOneComponent │ ├── Arch.cs │ ├── DefaultEcs.cs │ ├── Fennecs.cs │ ├── FlecsNet.cs │ ├── Frent.cs │ ├── FrifloEngineEcs.cs │ ├── HypEcs.cs │ ├── LeopotamEcs.cs │ ├── LeopotamEcsLite.cs │ ├── MonoGameExtended.cs │ ├── Morpeh.cs │ ├── Myriad.cs │ ├── RelEcs.cs │ ├── SveltoECS.cs │ ├── TinyEcs.cs │ └── _SystemWithOneComponent.cs ├── SystemWithThreeComponents │ ├── Arch.cs │ ├── DefaultEcs.cs │ ├── Fennecs.cs │ ├── FlecsNet.cs │ ├── Frent.cs │ ├── FrifloEngineEcs.cs │ ├── HypEcs.cs │ ├── LeopotamEcs.cs │ ├── LeopotamEcsLite.cs │ ├── MonoGameExtended.cs │ ├── Morpeh.cs │ ├── Myriad.cs │ ├── RelEcs.cs │ ├── SveltoECS.cs │ ├── TinyEcs.cs │ └── _SystemWithThreeComponents.cs ├── SystemWithTwoComponents │ ├── Arch.cs │ ├── DefaultEcs.cs │ ├── Fennecs.cs │ ├── FlecsNet.cs │ ├── Frent.cs │ ├── FrifloEngineEcs.cs │ ├── HypEcs.cs │ ├── LeopotamEcs.cs │ ├── LeopotamEcsLite.cs │ ├── MonoGameExtended.cs │ ├── Morpeh.cs │ ├── Myriad.cs │ ├── RelEcs.cs │ ├── SveltoECS.cs │ ├── TinyEcs.cs │ └── _SystemWithTwoComponents.cs └── SystemWithTwoComponentsMultipleComposition │ ├── Arch.cs │ ├── DefaultEcs.cs │ ├── Fennecs.cs │ ├── FlecsNet.cs │ ├── Frent.cs │ ├── FrifloEngineEcs.cs │ ├── HypEcs.cs │ ├── LeopotamEcs.cs │ ├── LeopotamEcsLite.cs │ ├── MonoGameExtended.cs │ ├── Morpeh.cs │ ├── Myriad.cs │ ├── RelEcs.cs │ ├── SveltoECS.cs │ ├── TinyEcs.cs │ └── _SystemWithTwoComponentsMultipleComposition.cs └── NuGet.config /.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 | -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /**/obj 2 | /**/bin 3 | /**/.vs 4 | /**/*.vspscc 5 | /**/*.user 6 | /**/*.snk 7 | /BenchmarkDotNet.Artifacts 8 | .idea/ 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 -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /results/Ecs.CSharp.Benchmark.CreateEntityWithOneComponent-report-github.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 3 | BenchmarkDotNet v0.13.12, Windows 11 (10.0.26100.3194) 4 | Intel Core i5-10505 CPU 3.20GHz, 1 CPU, 12 logical and 6 physical cores 5 | .NET SDK 9.0.102 6 | [Host] : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2 7 | Job-EBYXND : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2 8 | 9 | InvocationCount=1 UnrollFactor=1 10 | 11 | ``` 12 | | Method | EntityCount | Mean | Error | StdDev | Median | Gen0 | Gen1 | Gen2 | Allocated | 13 | |----------------- |------------ |------------:|------------:|------------:|------------:|----------:|----------:|----------:|------------:| 14 | | Frent_Bulk | 100000 | 768.6 μs | 15.14 μs | 24.45 μs | 769.5 μs | - | - | - | 3322.91 KB | 15 | | Frent | 100000 | 1,038.5 μs | 19.08 μs | 15.93 μs | 1,033.5 μs | - | - | - | 3322.91 KB | 16 | | FrifloEngineEcs | 100000 | 2,022.5 μs | 32.05 μs | 29.98 μs | 2,009.7 μs | - | - | - | 3381.74 KB | 17 | | LeopotamEcsLite | 100000 | 2,863.2 μs | 97.01 μs | 284.50 μs | 2,749.2 μs | - | - | - | 7151.08 KB | 18 | | Arch | 100000 | 3,694.8 μs | 69.18 μs | 124.75 μs | 3,655.5 μs | - | - | - | 3178.44 KB | 19 | | DefaultEcs | 100000 | 7,103.9 μs | 141.18 μs | 281.95 μs | 7,027.5 μs | - | - | - | 11321.11 KB | 20 | | FlecsNet | 100000 | 7,480.1 μs | 137.76 μs | 153.12 μs | 7,482.3 μs | - | - | - | 2.73 KB | 21 | | MonoGameExtended | 100000 | 8,282.6 μs | 216.57 μs | 592.85 μs | 8,247.3 μs | 1000.0000 | - | - | 16408.89 KB | 22 | | LeopotamEcs | 100000 | 9,003.1 μs | 252.12 μs | 735.44 μs | 8,947.2 μs | 1000.0000 | 1000.0000 | - | 13685.65 KB | 23 | | TinyEcs | 100000 | 11,316.8 μs | 217.74 μs | 242.01 μs | 11,327.0 μs | 1000.0000 | 1000.0000 | - | 7834.44 KB | 24 | | HypEcs | 100000 | 11,542.5 μs | 255.15 μs | 672.16 μs | 11,610.9 μs | 3000.0000 | 2000.0000 | 1000.0000 | 25829.38 KB | 25 | | Fennecs | 100000 | 12,146.8 μs | 242.24 μs | 460.88 μs | 12,168.0 μs | - | - | - | 13636.45 KB | 26 | | Myriad | 100000 | 17,310.6 μs | 337.52 μs | 438.87 μs | 17,246.5 μs | - | - | - | 7633.45 KB | 27 | | RelEcs | 100000 | 25,686.8 μs | 513.52 μs | 1,456.76 μs | 25,346.8 μs | 2000.0000 | - | - | 29706.66 KB | 28 | | SveltoECS | 100000 | 26,330.5 μs | 519.86 μs | 598.68 μs | 26,405.8 μs | - | - | - | 3.22 KB | 29 | | Morpeh_Stash | 100000 | 67,075.5 μs | 1,125.80 μs | 1,105.68 μs | 66,970.9 μs | 5000.0000 | 2000.0000 | 1000.0000 | 41305.76 KB | 30 | | Morpeh_Direct | 100000 | 67,753.8 μs | 1,329.16 μs | 1,364.95 μs | 67,708.2 μs | 5000.0000 | 2000.0000 | 1000.0000 | 41305.76 KB | 31 | -------------------------------------------------------------------------------- /results/Ecs.CSharp.Benchmark.CreateEntityWithThreeComponents-report-github.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 3 | BenchmarkDotNet v0.13.12, Windows 11 (10.0.26100.3194) 4 | Intel Core i5-10505 CPU 3.20GHz, 1 CPU, 12 logical and 6 physical cores 5 | .NET SDK 9.0.102 6 | [Host] : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2 7 | Job-EBYXND : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2 8 | 9 | InvocationCount=1 UnrollFactor=1 10 | 11 | ``` 12 | | Method | EntityCount | Mean | Error | StdDev | Median | Gen0 | Gen1 | Gen2 | Allocated | 13 | |----------------- |------------ |-----------:|----------:|----------:|-----------:|-----------:|----------:|----------:|------------:| 14 | | Frent | 100000 | 1.335 ms | 0.0083 ms | 0.0065 ms | 1.333 ms | - | - | - | 4104.34 KB | 15 | | Frent_Bulk | 100000 | 1.346 ms | 0.0255 ms | 0.0273 ms | 1.348 ms | - | - | - | 4104.34 KB | 16 | | FrifloEngineEcs | 100000 | 3.067 ms | 0.0612 ms | 0.0878 ms | 3.025 ms | 1000.0000 | 1000.0000 | 1000.0000 | 4412.23 KB | 17 | | LeopotamEcsLite | 100000 | 4.917 ms | 0.0978 ms | 0.2248 ms | 4.824 ms | - | - | - | 11248.14 KB | 18 | | Arch | 100000 | 8.351 ms | 0.1531 ms | 0.1357 ms | 8.322 ms | - | - | - | 3947.67 KB | 19 | | LeopotamEcs | 100000 | 11.649 ms | 0.2442 ms | 0.6685 ms | 11.704 ms | 1000.0000 | 1000.0000 | - | 15736.4 KB | 20 | | DefaultEcs | 100000 | 11.982 ms | 0.2385 ms | 0.4362 ms | 11.933 ms | - | - | - | 19516.68 KB | 21 | | FlecsNet | 100000 | 21.084 ms | 0.1915 ms | 0.1698 ms | 21.057 ms | - | - | - | 3.48 KB | 22 | | Myriad | 100000 | 26.959 ms | 0.3760 ms | 0.3333 ms | 26.892 ms | - | - | - | 8423.66 KB | 23 | | Fennecs | 100000 | 29.525 ms | 0.3449 ms | 0.3057 ms | 29.611 ms | - | - | - | 16713.12 KB | 24 | | TinyEcs | 100000 | 33.582 ms | 0.5998 ms | 0.5317 ms | 33.544 ms | 3000.0000 | 2000.0000 | 1000.0000 | 21316.55 KB | 25 | | HypEcs | 100000 | 35.524 ms | 0.7070 ms | 1.5668 ms | 35.439 ms | 8000.0000 | 1000.0000 | - | 68748.41 KB | 26 | | MonoGameExtended | 100000 | 39.518 ms | 0.7895 ms | 1.6480 ms | 39.200 ms | 2000.0000 | 1000.0000 | - | 30154.05 KB | 27 | | SveltoECS | 100000 | 52.785 ms | 0.9849 ms | 1.8500 ms | 52.140 ms | - | - | - | 4.64 KB | 28 | | Morpeh_Stash | 100000 | 70.168 ms | 1.3776 ms | 1.6399 ms | 69.869 ms | 5000.0000 | 3000.0000 | 1000.0000 | 44719.73 KB | 29 | | RelEcs | 100000 | 83.031 ms | 1.6248 ms | 1.9343 ms | 83.003 ms | 9000.0000 | 3000.0000 | - | 75699.76 KB | 30 | | Morpeh_Direct | 100000 | 179.589 ms | 3.5898 ms | 3.6865 ms | 178.515 ms | 12000.0000 | 7000.0000 | 2000.0000 | 83804.58 KB | 31 | -------------------------------------------------------------------------------- /results/Ecs.CSharp.Benchmark.CreateEntityWithTwoComponents-report-github.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 3 | BenchmarkDotNet v0.13.12, Windows 11 (10.0.26100.3194) 4 | Intel Core i5-10505 CPU 3.20GHz, 1 CPU, 12 logical and 6 physical cores 5 | .NET SDK 9.0.102 6 | [Host] : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2 7 | Job-EBYXND : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2 8 | 9 | InvocationCount=1 UnrollFactor=1 10 | 11 | ``` 12 | | Method | EntityCount | Mean | Error | StdDev | Median | Gen0 | Gen1 | Gen2 | Allocated | 13 | |----------------- |------------ |-----------:|----------:|-----------:|-----------:|-----------:|----------:|----------:|-------------:| 14 | | Frent | 100000 | 1.188 ms | 0.0065 ms | 0.0050 ms | 1.186 ms | - | - | - | 3713.63 KB | 15 | | Frent_Bulk | 100000 | 1.263 ms | 0.0241 ms | 0.0214 ms | 1.263 ms | - | - | - | 3713.63 KB | 16 | | FrifloEngineEcs | 100000 | 2.933 ms | 0.0584 ms | 0.1588 ms | 2.952 ms | 1000.0000 | 1000.0000 | 1000.0000 | 3898.13 KB | 17 | | Arch | 100000 | 3.864 ms | 0.0731 ms | 0.1820 ms | 3.807 ms | - | - | - | 3558.44 KB | 18 | | LeopotamEcsLite | 100000 | 4.599 ms | 0.2821 ms | 0.8319 ms | 4.426 ms | - | - | - | 9199.61 KB | 19 | | DefaultEcs | 100000 | 10.217 ms | 0.2039 ms | 0.4302 ms | 10.202 ms | - | - | - | 15418.9 KB | 20 | | LeopotamEcs | 100000 | 10.451 ms | 0.3019 ms | 0.8563 ms | 10.393 ms | 1000.0000 | 1000.0000 | - | 14711.02 KB | 21 | | FlecsNet | 100000 | 14.295 ms | 0.2811 ms | 0.2492 ms | 14.221 ms | - | - | - | 3.11 KB | 22 | | MonoGameExtended | 100000 | 17.426 ms | 0.4421 ms | 1.1724 ms | 17.811 ms | 1000.0000 | 1000.0000 | - | 23373.84 KB | 23 | | TinyEcs | 100000 | 19.518 ms | 0.4951 ms | 1.4443 ms | 18.828 ms | 2000.0000 | 1000.0000 | - | 13785.08 KB | 24 | | Fennecs | 100000 | 19.817 ms | 0.3851 ms | 0.4584 ms | 19.786 ms | - | - | - | 15174.45 KB | 25 | | HypEcs | 100000 | 21.669 ms | 0.3387 ms | 0.3002 ms | 21.641 ms | 5000.0000 | 3000.0000 | 1000.0000 | 45336.69 KB | 26 | | Myriad | 100000 | 23.799 ms | 0.4706 ms | 0.4402 ms | 23.629 ms | - | - | - | 8028.55 KB | 27 | | SveltoECS | 100000 | 39.648 ms | 0.7873 ms | 1.8089 ms | 39.372 ms | - | - | - | 4.14 KB | 28 | | RelEcs | 100000 | 60.414 ms | 1.2081 ms | 2.5217 ms | 60.124 ms | 5000.0000 | 2000.0000 | - | 50749.86 KB | 29 | | Morpeh_Stash | 100000 | 75.880 ms | 1.3733 ms | 2.4763 ms | 75.308 ms | 6000.0000 | 3000.0000 | 1000.0000 | 48133.7 KB | 30 | | Morpeh_Direct | 100000 | 271.755 ms | 5.6171 ms | 16.5622 ms | 277.597 ms | 18000.0000 | 9000.0000 | 1000.0000 | 128861.64 KB | 31 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/Contexts/FrifloEngineEcsContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Ecs.CSharp.Benchmark.Contexts.FrifloEngine_Components; 3 | using Friflo.Engine.ECS; 4 | 5 | namespace Ecs.CSharp.Benchmark.Contexts 6 | { 7 | namespace FrifloEngine_Components 8 | { 9 | internal struct Component1 : IComponent 10 | { 11 | public int Value; 12 | } 13 | 14 | internal struct Component2 : IComponent 15 | { 16 | public int Value; 17 | } 18 | 19 | internal struct Component3 : IComponent 20 | { 21 | public int Value; 22 | } 23 | } 24 | 25 | internal class FrifloEngineEcsBaseContext : IDisposable 26 | { 27 | protected EntityStore EntityStore { get; } 28 | public readonly ArchetypeQuery queryOne; 29 | public readonly ArchetypeQuery queryTwo; 30 | public readonly ArchetypeQuery queryThree; 31 | 32 | public readonly QueryJob jobOne; 33 | public readonly QueryJob jobTwo; 34 | public readonly QueryJob jobThree; 35 | public readonly QueryJob jobTwoWithComposition; 36 | 37 | 38 | protected FrifloEngineEcsBaseContext() 39 | { 40 | ParallelJobRunner runner = new ParallelJobRunner(Environment.ProcessorCount); 41 | EntityStore = new EntityStore(PidType.UsePidAsId) { JobRunner = runner }; 42 | queryOne = EntityStore.Query(); 43 | queryTwo = EntityStore.Query(); 44 | queryThree = EntityStore.Query(); 45 | 46 | jobOne = queryOne.ForEach(SystemWithOneComponent.FrifloEngineEcsContext.ForEach); 47 | jobTwo = queryTwo.ForEach(SystemWithTwoComponents.FrifloEngineEcsContext.ForEach); 48 | jobThree = queryThree.ForEach(SystemWithThreeComponents.FrifloEngineEcsContext.ForEach); 49 | jobTwoWithComposition = queryTwo.ForEach(SystemWithTwoComponentsMultipleComposition.FrifloEngineEcsContext.ForEach); 50 | } 51 | 52 | /// See padding notes 53 | /// 54 | /// 55 | /// has no influence on benchmarks performance for: SystemWith...Components 56 | /// e.g. Params[Params(0, 10)] at 57 | /// 58 | /// 59 | protected FrifloEngineEcsBaseContext(int entityCount, int padding, ComponentTypes componentTypes) : this() 60 | { 61 | 62 | EntityStore.EnsureCapacity(entityCount + (padding * entityCount)); 63 | 64 | Archetype archetype = EntityStore.GetArchetype(componentTypes); 65 | archetype.EnsureCapacity(entityCount); 66 | 67 | for (int index = 0; index < entityCount; index++) 68 | { 69 | for (int n = 0; n < padding; n++) 70 | { 71 | EntityStore.CreateEntity(); 72 | } 73 | archetype.CreateEntity(); 74 | } 75 | } 76 | 77 | public virtual void Dispose() 78 | { 79 | EntityStore.JobRunner?.Dispose(); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/Ecs.CSharp.Benchmark.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | latest 5 | net8.0 6 | Exe 7 | true 8 | true 9 | true 10 | AllEnabledByDefault 11 | latest 12 | true 13 | true 14 | $(NoWarn);NETSDK1206 15 | 16 | CHECK_CACHE_MISSES 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/SystemWithOneComponent/Morpeh.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BenchmarkDotNet.Attributes; 3 | using Ecs.CSharp.Benchmark.Contexts; 4 | using Scellecs.Morpeh; 5 | 6 | namespace Ecs.CSharp.Benchmark 7 | { 8 | public partial class SystemWithOneComponent 9 | { 10 | private sealed class MorpehContext : MorpehBaseContext 11 | { 12 | private sealed class DirectSystem : ISystem 13 | { 14 | public World World { get; set; } 15 | private Filter _filter; 16 | 17 | public void OnAwake() 18 | { 19 | _filter = World.Filter.With().Build(); 20 | } 21 | 22 | public void OnUpdate(float deltaTime) 23 | { 24 | foreach (Entity entity in _filter) 25 | { 26 | ++entity.GetComponent().Value; 27 | } 28 | } 29 | 30 | void IDisposable.Dispose() { } 31 | } 32 | 33 | private sealed class StashSystem : ISystem 34 | { 35 | public World World { get; set; } 36 | private Stash _stash1; 37 | private Filter _filter; 38 | 39 | public void OnAwake() 40 | { 41 | _stash1 = World.GetStash(); 42 | _filter = World.Filter.With().Build(); 43 | } 44 | 45 | public void OnUpdate(float deltaTime) 46 | { 47 | foreach (Entity entity in _filter) 48 | { 49 | ++_stash1.Get(entity).Value; 50 | } 51 | } 52 | 53 | public void Dispose() 54 | { 55 | _stash1.Dispose(); 56 | } 57 | } 58 | 59 | public ISystem MonoThreadDirectSystem { get; } 60 | public ISystem MonoThreadStashSystem { get; } 61 | 62 | public MorpehContext(int entityCount, int entityPadding) 63 | { 64 | MonoThreadDirectSystem = new DirectSystem { World = World }; 65 | MonoThreadDirectSystem.OnAwake(); 66 | 67 | MonoThreadStashSystem = new StashSystem { World = World }; 68 | MonoThreadStashSystem.OnAwake(); 69 | 70 | for (int i = 0; i < entityCount; ++i) 71 | { 72 | for (int j = 0; j < entityPadding; ++j) 73 | { 74 | World.CreateEntity(); 75 | } 76 | 77 | World.CreateEntity().AddComponent(); 78 | } 79 | 80 | World.Commit(); 81 | } 82 | } 83 | 84 | [Context] 85 | private readonly MorpehContext _context; 86 | 87 | [BenchmarkCategory(Categories.Morpeh)] 88 | [Benchmark] 89 | public void Morpeh_Direct() => _context.MonoThreadDirectSystem.OnUpdate(0f); 90 | 91 | [BenchmarkCategory(Categories.Morpeh)] 92 | [Benchmark] 93 | public void Morpeh_Stash() => _context.MonoThreadStashSystem.OnUpdate(0f); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /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/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/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/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/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/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 SystemWithThreeComponents 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, in Component3 c3) 18 | { 19 | c1.Value += c2.Value + c3.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 % 3) 41 | { 42 | case 0: 43 | padding.Set(); 44 | break; 45 | 46 | case 1: 47 | padding.Set(); 48 | break; 49 | 50 | case 2: 51 | padding.Set(); 52 | break; 53 | } 54 | } 55 | 56 | Entity entity = World.CreateEntity(); 57 | entity.Set(); 58 | entity.Set(new Component2 { Value = 1 }); 59 | entity.Set(new Component3 { Value = 1 }); 60 | } 61 | } 62 | 63 | public override void Dispose() 64 | { 65 | base.Dispose(); 66 | 67 | Runner.Dispose(); 68 | } 69 | } 70 | 71 | [Context] 72 | private readonly DefaultEcsContext _defaultEcs; 73 | 74 | [BenchmarkCategory(Categories.DefaultEcs)] 75 | [Benchmark] 76 | public void DefaultEcs_MonoThread() => _defaultEcs.MonoThreadEntitySetSystem.Update(0); 77 | 78 | [BenchmarkCategory(Categories.DefaultEcs)] 79 | [Benchmark] 80 | public void DefaultEcs_MultiThread() => _defaultEcs.MultiThreadEntitySetSystem.Update(0); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/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 SystemWithThreeComponents 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 % 3) 27 | { 28 | case 0: 29 | padding.Add(); 30 | break; 31 | case 1: 32 | padding.Add(); 33 | break; 34 | case 2: 35 | padding.Add(); 36 | break; 37 | } 38 | } 39 | 40 | World.Spawn().Add() 41 | .Add(new Component2 { Value = 1 }) 42 | .Add(new Component3 { Value = 1 }); 43 | } 44 | } 45 | } 46 | 47 | [BenchmarkCategory(Categories.Fennecs)] 48 | [Benchmark] 49 | public void Fennecs_ForEach() 50 | { 51 | _fennecs.query.For((ref Component1 c1, ref Component2 c2, ref Component3 c3) => c1.Value += c2.Value + c3.Value); 52 | } 53 | 54 | [BenchmarkCategory(Categories.Fennecs)] 55 | [Benchmark] 56 | public void Fennecs_Job() 57 | { 58 | _fennecs.query.Job(delegate(ref Component1 c1, ref Component2 c2, ref Component3 c3) { c1.Value += c2.Value + c3.Value; }, 1024); 59 | } 60 | 61 | [BenchmarkCategory(Categories.Fennecs)] 62 | [Benchmark] 63 | public void Fennecs_Raw() 64 | { 65 | _fennecs.query.Raw(delegate(Memory c1v, Memory c2v, Memory c3v) 66 | { 67 | var c1vs = c1v.Span; 68 | var c2vs = c2v.Span; 69 | var c3vs = c3v.Span; 70 | 71 | for (int i = 0; i < c1vs.Length; ++i) 72 | { 73 | ref Component1 c1 = ref c1vs[i]; 74 | c1.Value += c2vs[i].Value + c3vs[i].Value; 75 | } 76 | }); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /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/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/SystemWithThreeComponents/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 SystemWithThreeComponents 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() 16 | .Build(); 17 | query.Run((count, s1, s2, s3) => 18 | { 19 | for (int i = 0; i < count; i++) 20 | { 21 | s1[i].Value += s2[i].Value + s3[i].Value; 22 | } 23 | }); 24 | } 25 | } 26 | 27 | private sealed class MultiThreadRunSystem : ISystem 28 | { 29 | public void Run(World world) 30 | { 31 | Query query = world.Query() 32 | .Build(); 33 | query.RunParallel((count, s1, s2, s3) => 34 | { 35 | for (int i = 0; i < count; i++) 36 | { 37 | s1[i].Value += s2[i].Value + s3[i].Value; 38 | } 39 | }); 40 | } 41 | } 42 | 43 | public ISystem MonoThreadSystem { get; } = new MonoThreadRunSystem(); 44 | public ISystem MultiThreadSystem { get; } = new MultiThreadRunSystem(); 45 | 46 | public HypEcsContext(int entityCount, int entityPadding) 47 | { 48 | for (int i = 0; i < entityCount; ++i) 49 | { 50 | for (int j = 0; j < entityPadding; ++j) 51 | { 52 | EntityBuilder padding = World.Spawn(); 53 | switch (j % 3) 54 | { 55 | case 0: 56 | padding.Add(new Component1()); 57 | break; 58 | 59 | case 1: 60 | padding.Add(new Component2()); 61 | break; 62 | 63 | case 2: 64 | padding.Add(new Component3()); 65 | break; 66 | } 67 | } 68 | 69 | World.Spawn() 70 | .Add(new Component1()) 71 | .Add(new Component2 { Value = 1 }) 72 | .Add(new Component3 { Value = 1 }); 73 | } 74 | } 75 | } 76 | 77 | [Context] private readonly HypEcsContext _hypEcs; 78 | 79 | [BenchmarkCategory(Categories.HypEcs)] 80 | [Benchmark] 81 | public void HypEcs_MonoThread() => _hypEcs.MonoThreadSystem.Run(_hypEcs.World); 82 | 83 | [BenchmarkCategory(Categories.HypEcs)] 84 | [Benchmark] 85 | public void HypEcs_MultiThread() => _hypEcs.MultiThreadSystem.Run(_hypEcs.World); 86 | } 87 | } -------------------------------------------------------------------------------- /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/SystemWithThreeComponents/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 SystemWithThreeComponents 8 | { 9 | private sealed class LeopotamEcsLiteContext : LeopotamEcsLiteBaseContext 10 | { 11 | private sealed class MonoThreadRunSystem : IEcsInitSystem, IEcsRunSystem 12 | { 13 | private EcsFilter _filter; 14 | private EcsPool _c1; 15 | private EcsPool _c2; 16 | private EcsPool _c3; 17 | 18 | public void Init(IEcsSystems systems) 19 | { 20 | EcsWorld world = systems.GetWorld(); 21 | 22 | _filter = world.Filter().Inc().Inc().End(); 23 | _c1 = world.GetPool(); 24 | _c2 = world.GetPool(); 25 | _c3 = world.GetPool(); 26 | } 27 | 28 | public void Run(IEcsSystems systems) 29 | { 30 | int[] entities = _filter.GetRawEntities(); 31 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++) 32 | { 33 | _c1.Get(entities[i]).Value += _c2.Get(entities[i]).Value + _c3.Get(entities[i]).Value; 34 | } 35 | } 36 | } 37 | 38 | public IEcsSystems MonoThreadSystem { get; } 39 | 40 | public LeopotamEcsLiteContext(int entityCount, int entityPadding) 41 | { 42 | MonoThreadSystem = new EcsSystems(World).Add(new MonoThreadRunSystem()); 43 | 44 | MonoThreadSystem.Init(); 45 | 46 | EcsPool c1 = World.GetPool(); 47 | EcsPool c2 = World.GetPool(); 48 | EcsPool c3 = World.GetPool(); 49 | 50 | for (int i = 0; i < entityCount; ++i) 51 | { 52 | for (int j = 0; j < entityPadding; ++j) 53 | { 54 | int padding = World.NewEntity(); 55 | switch (j % 3) 56 | { 57 | case 0: 58 | c1.Add(padding); 59 | break; 60 | 61 | case 1: 62 | c2.Add(padding); 63 | break; 64 | 65 | case 2: 66 | c3.Add(padding); 67 | break; 68 | } 69 | } 70 | 71 | int entity = World.NewEntity(); 72 | c1.Add(entity); 73 | c2.Add(entity) = new Component2 { Value = 1 }; 74 | c3.Add(entity) = new Component3 { Value = 1 }; 75 | } 76 | } 77 | } 78 | 79 | [Context] 80 | private readonly LeopotamEcsLiteContext _leopotamEcsLite; 81 | 82 | [BenchmarkCategory(Categories.LeopotamEcsLite)] 83 | [Benchmark] 84 | public void LeopotamEcsLite() => _leopotamEcsLite.MonoThreadSystem.Run(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/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 SystemWithThreeComponents 10 | { 11 | private sealed class MonoGameExtendedContext : MonoGameExtendedBaseContext 12 | { 13 | public sealed class UpdateSystem : EntityUpdateSystem 14 | { 15 | private ComponentMapper _c1; 16 | private ComponentMapper _c2; 17 | private ComponentMapper _c3; 18 | 19 | public UpdateSystem() 20 | : base(Aspect.All(typeof(Component1), typeof(Component2), typeof(Component3))) 21 | { } 22 | 23 | public override void Initialize(IComponentMapperService mapperService) 24 | { 25 | _c1 = mapperService.GetMapper(); 26 | _c2 = mapperService.GetMapper(); 27 | _c3 = mapperService.GetMapper(); 28 | } 29 | 30 | public override void Update(GameTime gameTime) 31 | { 32 | foreach (int entityId in ActiveEntities) 33 | { 34 | _c1.Get(entityId).Value += _c2.Get(entityId).Value + _c3.Get(entityId).Value; 35 | } 36 | } 37 | } 38 | 39 | private readonly UpdateSystem _system; 40 | 41 | public new World World { get; } 42 | 43 | public GameTime Time { get; } 44 | 45 | public MonoGameExtendedContext(int entityCount, int entityPadding) 46 | { 47 | _system = new UpdateSystem(); 48 | World = new WorldBuilder().AddSystem(_system).Build(); 49 | Time = new GameTime(); 50 | 51 | for (int i = 0; i < entityCount; ++i) 52 | { 53 | for (int j = 0; j < entityPadding; ++j) 54 | { 55 | Entity padding = World.CreateEntity(); 56 | switch (j % 3) 57 | { 58 | case 0: 59 | padding.Attach(new Component1()); 60 | break; 61 | 62 | case 1: 63 | padding.Attach(new Component2()); 64 | break; 65 | 66 | case 2: 67 | padding.Attach(new Component3()); 68 | break; 69 | } 70 | } 71 | 72 | Entity entity = World.CreateEntity(); 73 | entity.Attach(new Component1()); 74 | entity.Attach(new Component2 { Value = 1 }); 75 | entity.Attach(new Component3 { Value = 1 }); 76 | } 77 | } 78 | 79 | public override void Dispose() 80 | { 81 | World.Dispose(); 82 | _system.Dispose(); 83 | 84 | base.Dispose(); 85 | } 86 | } 87 | 88 | [Context] 89 | private readonly MonoGameExtendedContext _monoGameExtended; 90 | 91 | [BenchmarkCategory(Categories.MonoGameExtended)] 92 | [Benchmark] 93 | public void MonoGameExtended() => _monoGameExtended.World.Update(_monoGameExtended.Time); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /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/SystemWithThreeComponents/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 SystemWithThreeComponents 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, NB c3, int count) = entitiesDB.QueryEntities(Group); 23 | 24 | for (int i = 0; i < count; i++) 25 | { 26 | c1[i].Value += c2[i].Value + c3[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 Padding3Entity : GenericEntityDescriptor 38 | { } 39 | 40 | public sealed class Entity : GenericEntityDescriptor 41 | { } 42 | 43 | public SveltoEngine Engine { get; } 44 | 45 | public SveltoECSContext(int entityCount, int entityPadding) 46 | { 47 | Engine = new SveltoEngine(); 48 | Root.AddEngine(Engine); 49 | 50 | uint id = 0; 51 | for (int i = 0; i < entityCount; ++i) 52 | { 53 | for (int j = 0; j < entityPadding; ++j) 54 | { 55 | switch (j % 3) 56 | { 57 | case 0: 58 | Factory.BuildEntity(id++, Group); 59 | break; 60 | 61 | case 1: 62 | Factory.BuildEntity(id++, Group); 63 | break; 64 | 65 | case 2: 66 | Factory.BuildEntity(id++, Group); 67 | break; 68 | } 69 | } 70 | 71 | EntityInitializer entity = Factory.BuildEntity(id++, Group); 72 | entity.GetOrAdd() = new Component2 { Value = 1 }; 73 | entity.GetOrAdd() = new Component3 { Value = 1 }; 74 | } 75 | 76 | Scheduler.SubmitEntities(); 77 | } 78 | } 79 | 80 | [Context] 81 | private readonly SveltoECSContext _sveltoECS; 82 | 83 | [Benchmark] 84 | public void SveltoECS() => _sveltoECS.Engine.Update(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/SystemWithTwoComponents/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 SystemWithTwoComponents 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, Chunk component2, ChunkEntities entities) 19 | { 20 | Span component1Span = component1.Span; 21 | Span component2Span = component2.Span; 22 | for (int n = 0; n < component1Span.Length; n++) 23 | { 24 | Update(ref component1Span[n], ref component2Span[n]); 25 | } 26 | } 27 | } 28 | 29 | [Context] 30 | private readonly FrifloEngineEcsContext _frifloEngineEcs; 31 | 32 | [BenchmarkCategory(Categories.FrifloEngineEcs)] 33 | [Benchmark] 34 | public void FrifloEngineEcs_MonoThread() 35 | { 36 | foreach ((Chunk component1, Chunk component2, ChunkEntities _) in _frifloEngineEcs.queryTwo.Chunks) 37 | { 38 | Span component1Span = component1.Span; 39 | Span component2Span = component2.Span; 40 | for (int n = 0; n < component1Span.Length; n++) 41 | { 42 | Update(ref component1Span[n], ref component2Span[n]); 43 | } 44 | } 45 | } 46 | 47 | [BenchmarkCategory(Categories.FrifloEngineEcs)] 48 | [Benchmark] 49 | public void FrifloEngineEcs_MultiThread() 50 | { 51 | _frifloEngineEcs.jobTwo.RunParallel(); 52 | } 53 | 54 | private static void Update(ref Component1 c1, ref Component2 c2) 55 | { 56 | c1.Value += c2.Value; 57 | } 58 | 59 | [BenchmarkCategory(Categories.FrifloEngineEcs)] 60 | [Benchmark] 61 | public void FrifloEngineEcs_SIMD_MonoThread() 62 | { 63 | foreach ((Chunk component1, Chunk component2, ChunkEntities _) 64 | in _frifloEngineEcs.queryTwo.Chunks) 65 | { 66 | Span component1Span = component1.AsSpan256(); // Length - multiple of 8 67 | Span component2Span = component2.AsSpan256(); // Length - multiple of 8 68 | int step = component1.StepSpan256; // step = 8 69 | for (int n = 0; n < component1Span.Length; n += step) 70 | { 71 | Span component1Slice = component1Span.Slice(n, step); 72 | Vector256 value1 = Vector256.Create(component1Slice); 73 | Vector256 value2 = Vector256.Create(component2Span.Slice(n, step)); 74 | Vector256 result = Vector256.Add(value1, value2); // execute 8 add instructions at once 75 | result.CopyTo(component1Slice); 76 | } 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/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 SystemWithTwoComponents 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, s2) => 17 | { 18 | for (int i = 0; i < count; i++) 19 | { 20 | s1[i].Value += s2[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, s2) => 32 | { 33 | for (int i = 0; i < count; i++) 34 | { 35 | s1[i].Value += s2[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 | EntityBuilder padding = World.Spawn(); 51 | switch (j % 2) 52 | { 53 | case 0: 54 | padding.Add(new Component1()); 55 | break; 56 | 57 | case 1: 58 | padding.Add(new Component2()); 59 | break; 60 | } 61 | } 62 | 63 | World.Spawn() 64 | .Add(new Component1()) 65 | .Add(new Component2 { Value = 1 }); 66 | } 67 | } 68 | } 69 | 70 | [Context] private readonly HypEcsContext _hypEcs; 71 | 72 | [BenchmarkCategory(Categories.HypEcs)] 73 | [Benchmark] 74 | public void HypEcs_MonoThread() => _hypEcs.MonoThreadSystem.Run(_hypEcs.World); 75 | 76 | [BenchmarkCategory(Categories.HypEcs)] 77 | [Benchmark] 78 | public void HypEcs_MultiThread() => _hypEcs.MultiThreadSystem.Run(_hypEcs.World); 79 | } 80 | } -------------------------------------------------------------------------------- /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/SystemWithTwoComponents/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 SystemWithTwoComponents 8 | { 9 | private sealed class LeopotamEcsLiteContext : LeopotamEcsLiteBaseContext 10 | { 11 | private sealed class MonoThreadRunSystem : IEcsInitSystem, IEcsRunSystem 12 | { 13 | private EcsFilter _filter; 14 | private EcsPool _c1; 15 | private EcsPool _c2; 16 | 17 | public void Init(IEcsSystems systems) 18 | { 19 | EcsWorld world = systems.GetWorld(); 20 | 21 | _filter = world.Filter().Inc().End(); 22 | _c1 = world.GetPool(); 23 | _c2 = world.GetPool(); 24 | } 25 | 26 | public void Run(IEcsSystems systems) 27 | { 28 | int[] entities = _filter.GetRawEntities(); 29 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++) 30 | { 31 | _c1.Get(entities[i]).Value += _c2.Get(entities[i]).Value; 32 | } 33 | } 34 | } 35 | 36 | public IEcsSystems MonoThreadSystem { get; } 37 | 38 | public LeopotamEcsLiteContext(int entityCount, int entityPadding) 39 | { 40 | MonoThreadSystem = new EcsSystems(World).Add(new MonoThreadRunSystem()); 41 | 42 | MonoThreadSystem.Init(); 43 | 44 | EcsPool c1 = World.GetPool(); 45 | EcsPool c2 = World.GetPool(); 46 | 47 | for (int i = 0; i < entityCount; ++i) 48 | { 49 | for (int j = 0; j < entityPadding; ++j) 50 | { 51 | int padding = World.NewEntity(); 52 | switch (j % 2) 53 | { 54 | case 0: 55 | c1.Add(padding); 56 | break; 57 | 58 | case 1: 59 | c2.Add(padding); 60 | break; 61 | } 62 | } 63 | 64 | int entity = World.NewEntity(); 65 | c1.Add(entity); 66 | c2.Add(entity) = new Component2 { Value = 1 }; 67 | } 68 | } 69 | } 70 | 71 | [Context] 72 | private readonly LeopotamEcsLiteContext _leopotamEcsLite; 73 | 74 | [BenchmarkCategory(Categories.LeopotamEcsLite)] 75 | [Benchmark] 76 | public void LeopotamEcsLite() => _leopotamEcsLite.MonoThreadSystem.Run(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /source/Ecs.CSharp.Benchmark/SystemWithTwoComponents/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 SystemWithTwoComponents 10 | { 11 | private sealed class MonoGameExtendedContext : MonoGameExtendedBaseContext 12 | { 13 | public sealed class UpdateSystem : EntityUpdateSystem 14 | { 15 | private ComponentMapper _c1; 16 | private ComponentMapper _c2; 17 | 18 | public UpdateSystem() 19 | : base(Aspect.All(typeof(Component1), typeof(Component2))) 20 | { } 21 | 22 | public override void Initialize(IComponentMapperService mapperService) 23 | { 24 | _c1 = mapperService.GetMapper(); 25 | _c2 = mapperService.GetMapper(); 26 | } 27 | 28 | public override void Update(GameTime gameTime) 29 | { 30 | foreach (int entityId in ActiveEntities) 31 | { 32 | _c1.Get(entityId).Value += _c2.Get(entityId).Value; 33 | } 34 | } 35 | } 36 | 37 | private readonly UpdateSystem _system; 38 | 39 | public new World World { get; } 40 | 41 | public GameTime Time { get; } 42 | 43 | public MonoGameExtendedContext(int entityCount, int entityPadding) 44 | { 45 | _system = new UpdateSystem(); 46 | World = new WorldBuilder().AddSystem(_system).Build(); 47 | Time = new GameTime(); 48 | 49 | for (int i = 0; i < entityCount; ++i) 50 | { 51 | for (int j = 0; j < entityPadding; ++j) 52 | { 53 | Entity padding = World.CreateEntity(); 54 | switch (j % 2) 55 | { 56 | case 0: 57 | padding.Attach(new Component1()); 58 | break; 59 | 60 | case 1: 61 | padding.Attach(new Component2()); 62 | break; 63 | } 64 | } 65 | 66 | Entity entity = World.CreateEntity(); 67 | entity.Attach(new Component1()); 68 | entity.Attach(new Component2 { Value = 1 }); 69 | } 70 | } 71 | 72 | public override void Dispose() 73 | { 74 | World.Dispose(); 75 | _system.Dispose(); 76 | 77 | base.Dispose(); 78 | } 79 | } 80 | 81 | [Context] 82 | private readonly MonoGameExtendedContext _monoGameExtended; 83 | 84 | [BenchmarkCategory(Categories.MonoGameExtended)] 85 | [Benchmark] 86 | public void MonoGameExtended() => _monoGameExtended.World.Update(_monoGameExtended.Time); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /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/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/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/_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/SystemWithTwoComponentsMultipleComposition/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 SystemWithTwoComponentsMultipleComposition 11 | { 12 | private sealed partial class DefaultEcsContext : DefaultEcsBaseContext 13 | { 14 | private record struct Padding1(); 15 | 16 | private record struct Padding2(); 17 | 18 | private record struct Padding3(); 19 | 20 | private record struct Padding4(); 21 | 22 | private sealed partial class EntitySetSystem : AEntitySetSystem 23 | { 24 | [Update] 25 | private static void Update(ref Component1 c1, in Component2 c2) 26 | { 27 | c1.Value += c2.Value; 28 | } 29 | } 30 | 31 | public IParallelRunner Runner { get; } 32 | 33 | public ISystem MonoThreadEntitySetSystem { get; } 34 | 35 | public ISystem MultiThreadEntitySetSystem { get; } 36 | 37 | public DefaultEcsContext(int entityCount) 38 | { 39 | Runner = new DefaultParallelRunner(Environment.ProcessorCount); 40 | MonoThreadEntitySetSystem = new EntitySetSystem(World); 41 | MultiThreadEntitySetSystem = new EntitySetSystem(World, Runner); 42 | 43 | for (int i = 0; i < entityCount; ++i) 44 | { 45 | Entity entity = World.CreateEntity(); 46 | entity.Set(); 47 | entity.Set(new Component2 { Value = 1 }); 48 | 49 | switch (i % 4) 50 | { 51 | case 0: 52 | entity.Set(); 53 | break; 54 | 55 | case 1: 56 | entity.Set(); 57 | break; 58 | 59 | case 2: 60 | entity.Set(); 61 | break; 62 | 63 | case 3: 64 | entity.Set(); 65 | break; 66 | } 67 | } 68 | } 69 | 70 | public override void Dispose() 71 | { 72 | base.Dispose(); 73 | 74 | Runner.Dispose(); 75 | } 76 | } 77 | 78 | [Context] 79 | private readonly DefaultEcsContext _defaultEcs; 80 | 81 | [BenchmarkCategory(Categories.DefaultEcs)] 82 | [Benchmark] 83 | public void DefaultEcs_MonoThread() => _defaultEcs.MonoThreadEntitySetSystem.Update(0); 84 | 85 | [BenchmarkCategory(Categories.DefaultEcs)] 86 | [Benchmark] 87 | public void DefaultEcs_MultiThread() => _defaultEcs.MultiThreadEntitySetSystem.Update(0); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /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/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/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>(); 32 | } 33 | 34 | public Query Query; 35 | 36 | struct Padding1; 37 | struct Padding2; 38 | struct Padding3; 39 | struct Padding4; 40 | } 41 | 42 | internal struct Sum : IAction 43 | { 44 | public void Run(ref Component1 t0, ref Component2 t1) 45 | { 46 | t0.Value += t1.Value; 47 | } 48 | } 49 | 50 | [BenchmarkCategory(Categories.Frent)] 51 | [Benchmark] 52 | public void Frent_QueryInline() 53 | { 54 | _frent.Query.Inline(default); 55 | } 56 | 57 | [BenchmarkCategory(Categories.Frent)] 58 | [Benchmark] 59 | public void Frent_Simd() 60 | { 61 | foreach ((var s1, var s2) in _frent.Query.EnumerateChunks()) 62 | { 63 | int len = s1.Length - (s1.Length & 7); 64 | 65 | Span> ints = MemoryMarshal.Cast>(s1.Slice(0, len)); 66 | Span> a = MemoryMarshal.Cast>(s2.Slice(0, len))[..ints.Length]; 67 | 68 | for (int i = 0; i < ints.Length; i++) 69 | ints[i] += a[i]; 70 | 71 | for (int i = len; i < s1.Length; i++) 72 | s1[i].Value += s2[i].Value; 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /source/Ecs.CSharp.Benchmark/SystemWithTwoComponentsMultipleComposition/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 SystemWithTwoComponentsMultipleComposition 8 | { 9 | private sealed class HypEcsContext : HypEcsBaseContext 10 | { 11 | private struct Padding1 12 | { 13 | } 14 | 15 | private struct Padding2 16 | { 17 | } 18 | 19 | private struct Padding3 20 | { 21 | } 22 | 23 | private struct Padding4 24 | { 25 | } 26 | 27 | private sealed class MonoThreadRunSystem : ISystem 28 | { 29 | public void Run(World world) 30 | { 31 | Query query = world.Query().Build(); 32 | query.Run((count, s1, s2) => 33 | { 34 | for (int i = 0; i < count; i++) 35 | { 36 | s1[i].Value += s2[i].Value; 37 | } 38 | }); 39 | } 40 | } 41 | 42 | private sealed class MultiThreadRunSystem : ISystem 43 | { 44 | public void Run(World world) 45 | { 46 | Query query = world.Query().Build(); 47 | query.RunParallel((count, s1, s2) => 48 | { 49 | for (int i = 0; i < count; i++) 50 | { 51 | s1[i].Value += s2[i].Value; 52 | } 53 | }); 54 | } 55 | } 56 | 57 | public ISystem MonoThreadSystem { get; } = new MonoThreadRunSystem(); 58 | public ISystem MultiThreadSystem { get; } = new MultiThreadRunSystem(); 59 | 60 | public HypEcsContext(int entityCount) 61 | { 62 | for (int i = 0; i < entityCount; ++i) 63 | { 64 | EntityBuilder entity = World.Spawn() 65 | .Add(new Component1()) 66 | .Add(new Component2 { Value = 1 }); 67 | 68 | switch (i % 4) 69 | { 70 | case 0: 71 | entity.Add(); 72 | break; 73 | 74 | case 1: 75 | entity.Add(); 76 | break; 77 | 78 | case 2: 79 | entity.Add(); 80 | break; 81 | 82 | case 3: 83 | entity.Add(); 84 | break; 85 | } 86 | } 87 | } 88 | } 89 | 90 | [Context] private readonly HypEcsContext _hypEcs; 91 | 92 | [BenchmarkCategory(Categories.HypEcs)] 93 | [Benchmark] 94 | public void HypEcs_MonoThread() => _hypEcs.MonoThreadSystem.Run(_hypEcs.World); 95 | 96 | [BenchmarkCategory(Categories.HypEcs)] 97 | [Benchmark] 98 | public void HypEcs_MultiThread() => _hypEcs.MultiThreadSystem.Run(_hypEcs.World); 99 | } 100 | } -------------------------------------------------------------------------------- /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/SystemWithTwoComponentsMultipleComposition/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 SystemWithTwoComponentsMultipleComposition 8 | { 9 | private sealed class LeopotamEcsLiteContext : LeopotamEcsLiteBaseContext 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 : IEcsInitSystem, IEcsRunSystem 20 | { 21 | private EcsFilter _filter; 22 | private EcsPool _c1; 23 | private EcsPool _c2; 24 | 25 | public void Init(IEcsSystems systems) 26 | { 27 | EcsWorld world = systems.GetWorld(); 28 | 29 | _filter = world.Filter().Inc().End(); 30 | _c1 = world.GetPool(); 31 | _c2 = world.GetPool(); 32 | } 33 | 34 | public void Run(IEcsSystems systems) 35 | { 36 | int[] entities = _filter.GetRawEntities(); 37 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++) 38 | { 39 | _c1.Get(entities[i]).Value += _c2.Get(entities[i]).Value; 40 | } 41 | } 42 | } 43 | 44 | public IEcsSystems MonoThreadSystem { get; } 45 | 46 | public LeopotamEcsLiteContext(int entityCount) 47 | { 48 | MonoThreadSystem = new EcsSystems(World).Add(new MonoThreadRunSystem()); 49 | 50 | MonoThreadSystem.Init(); 51 | 52 | EcsPool c1 = World.GetPool(); 53 | EcsPool c2 = World.GetPool(); 54 | 55 | EcsPool p1 = World.GetPool(); 56 | EcsPool p2 = World.GetPool(); 57 | EcsPool p3 = World.GetPool(); 58 | EcsPool p4 = World.GetPool(); 59 | 60 | for (int i = 0; i < entityCount; ++i) 61 | { 62 | int entity = World.NewEntity(); 63 | c1.Add(entity); 64 | c2.Add(entity) = new Component2 { Value = 1 }; 65 | 66 | switch (i % 4) 67 | { 68 | case 0: 69 | p1.Add(entity); 70 | break; 71 | 72 | case 1: 73 | p2.Add(entity); 74 | break; 75 | 76 | case 2: 77 | p3.Add(entity); 78 | break; 79 | 80 | case 3: 81 | p4.Add(entity); 82 | break; 83 | } 84 | } 85 | } 86 | } 87 | 88 | [Context] 89 | private readonly LeopotamEcsLiteContext _leopotamEcsLite; 90 | 91 | [BenchmarkCategory(Categories.LeopotamEcsLite)] 92 | [Benchmark] 93 | public void LeopotamEcsLite() => _leopotamEcsLite.MonoThreadSystem.Run(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /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/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 SystemWithTwoComponentsMultipleComposition 10 | { 11 | private sealed class SveltoECSContext : SveltoECSBaseContext 12 | { 13 | private record struct Padding1() : IEntityComponent; 14 | 15 | private record struct Padding2() : IEntityComponent; 16 | 17 | private record struct Padding3() : IEntityComponent; 18 | 19 | private record struct Padding4() : IEntityComponent; 20 | 21 | public sealed class SveltoEngine : IQueryingEntitiesEngine 22 | { 23 | public EntitiesDB entitiesDB { get; set; } 24 | 25 | public void Ready() 26 | { } 27 | 28 | public void Update() 29 | { 30 | (NB c1, NB c2, int count) = entitiesDB.QueryEntities(Group); 31 | 32 | for (int i = 0; i < count; i++) 33 | { 34 | c1[i].Value += c2[i].Value; 35 | } 36 | } 37 | } 38 | 39 | private sealed class Entity1 : GenericEntityDescriptor 40 | { } 41 | 42 | private sealed class Entity2 : GenericEntityDescriptor 43 | { } 44 | 45 | private sealed class Entity3 : GenericEntityDescriptor 46 | { } 47 | 48 | private sealed class Entity4 : GenericEntityDescriptor 49 | { } 50 | 51 | private sealed class Entity : GenericEntityDescriptor 52 | { } 53 | 54 | public SveltoEngine Engine { get; } 55 | 56 | public SveltoECSContext(int entityCount) 57 | { 58 | Engine = new SveltoEngine(); 59 | Root.AddEngine(Engine); 60 | 61 | uint id = 0; 62 | for (int i = 0; i < entityCount; ++i) 63 | { 64 | EntityInitializer entity = (i % 4) switch 65 | { 66 | 0 => Factory.BuildEntity(id++, Group), 67 | 1 => Factory.BuildEntity(id++, Group), 68 | 2 => Factory.BuildEntity(id++, Group), 69 | _ => Factory.BuildEntity(id++, Group) 70 | }; 71 | 72 | entity.GetOrAdd() = new Component2 { Value = 1 }; 73 | } 74 | 75 | Scheduler.SubmitEntities(); 76 | } 77 | } 78 | 79 | [Context] 80 | private readonly SveltoECSContext _sveltoECS; 81 | 82 | [BenchmarkCategory(Categories.SveltoECS)] 83 | [Benchmark] 84 | public void SveltoECS() => _sveltoECS.Engine.Update(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /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/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/NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | --------------------------------------------------------------------------------