├── .github └── workflows │ ├── benchmark.yml │ └── test.yml ├── .gitignore ├── .gitmodules ├── .idea └── .idea.Benchmark │ └── .idea │ ├── .gitignore │ ├── .name │ ├── encodings.xml │ ├── indexLayout.xml │ └── vcs.xml ├── ArrayECS ├── ArrayECS.csproj └── World.cs ├── Benchmark.Arch ├── ArchContext.cs ├── Benchmark.Arch.csproj └── System.cs ├── Benchmark.ArrayECS ├── ArrayECSContext.cs └── Benchmark.ArrayECS.csproj ├── Benchmark.DefaultECS ├── Benchmark.DefaultECS.csproj ├── DefaultECSContext.cs └── System.cs ├── Benchmark.DragonECS ├── Benchmark.DragonECS.csproj ├── DragonECSContext.cs ├── GenericAspects.cs └── PointerInvocationSystem.cs ├── Benchmark.Fennecs ├── Benchmark.Fennecs.csproj ├── FennecsContext.cs └── System.cs ├── Benchmark.FlecsNET ├── Benchmark.FlecsNET.csproj └── FlecsNETContext.cs ├── Benchmark.FriFlo ├── Benchmark.FriFlo.csproj ├── FriFloContext.cs └── FriFloSystem.cs ├── Benchmark.LeoEcs ├── Benchmark.LeoEcs.csproj ├── LeoEcsContext.cs └── System.cs ├── Benchmark.LeoEcsLite ├── Benchmark.LeoEcsLite.csproj ├── LeoEcsLiteContext.cs └── System.cs ├── Benchmark.MassiveECS ├── Benchmark.MassiveECS.csproj └── MassiveEcsContext.cs ├── Benchmark.Morpeh ├── Benchmark.Morpeh.csproj ├── MorpehContext.cs └── PointerInvocationStashSystem.cs ├── Benchmark.StaticEcs ├── Benchmark.StaticEcs.csproj └── StaticEcsContext.cs ├── Benchmark.TinyECS ├── Benchmark.TinyECS.csproj └── TinyEcsContext.cs ├── Benchmark.Xeno ├── Benchmark.Xeno.csproj └── XenoContext.cs ├── Benchmark._Context ├── ArrayExtensions.cs ├── Benchmark._Context.csproj ├── Context.cs ├── IBenchmarkContext.cs └── Ignore.cs ├── Benchmark._Generator ├── Benchmark._Generator.csproj ├── BenchmarkGenerator2.cs ├── MethodInliner.cs ├── Properties │ └── launchSettings.json └── SymbolExtensions.cs ├── Benchmark._Tests ├── Benchmark._Tests.csproj ├── Benchmark._Tests.csproj.DotSettings ├── Helper.cs ├── TestBenchmarks.cs ├── TestContexts.cs └── TestOverhead.cs ├── Benchmark.sh ├── Benchmark.sln ├── Benchmark.sln.DotSettings ├── Benchmark.sln.DotSettings.user ├── Benchmark ├── Benchmark.csproj ├── Benchmarks │ ├── Entities │ │ ├── AddComponent │ │ │ ├── Add1Component.cs │ │ │ ├── Add1ComponentRandomOrder.cs │ │ │ ├── Add1RandomComponent.cs │ │ │ ├── Add1RandomComponentRandomOrder.cs │ │ │ ├── Add2Components.cs │ │ │ ├── Add2ComponentsRandomOrder.cs │ │ │ ├── Add2RandomComponents.cs │ │ │ ├── Add2RandomComponentsRandomOrder.cs │ │ │ ├── Add3Components.cs │ │ │ ├── Add3ComponentsRandomOrder.cs │ │ │ ├── Add3RandomComponents.cs │ │ │ ├── Add3RandomComponentsRandomOrder.cs │ │ │ ├── Add4Components.cs │ │ │ └── Add4ComponentsRandomOrder.cs │ │ ├── CreateEntity │ │ │ ├── CreateEmptyEntity.cs │ │ │ ├── CreateEntityWith1Component.cs │ │ │ ├── CreateEntityWith1RandomComponent.cs │ │ │ ├── CreateEntityWith2Components.cs │ │ │ ├── CreateEntityWith2RandomComponents.cs │ │ │ ├── CreateEntityWith3Components.cs │ │ │ ├── CreateEntityWith3RandomComponents.cs │ │ │ └── CreateEntityWith4Components.cs │ │ ├── DeleteEntity │ │ │ └── DeleteEntity.cs │ │ ├── RemoveComponent │ │ │ ├── Remove1Component.cs │ │ │ ├── Remove1ComponentRandomOrder.cs │ │ │ ├── Remove2Components.cs │ │ │ ├── Remove2ComponentsRandomOrder.cs │ │ │ ├── Remove3Components.cs │ │ │ ├── Remove3ComponentsRandomOrder.cs │ │ │ ├── Remove4Components.cs │ │ │ └── Remove4ComponentsRandomOrder.cs │ │ └── StructuralChanges │ │ │ ├── FourRemoveOneComponent.cs │ │ │ ├── FourRemoveThreeComponents.cs │ │ │ ├── FourRemoveTwoComponents.cs │ │ │ ├── OneAddOneComponent.cs │ │ │ ├── OneAddThreeComponents.cs │ │ │ ├── OneAddTwoComponents.cs │ │ │ ├── ThreeAddOneComponent.cs │ │ │ ├── ThreeRemoveOneComponent.cs │ │ │ ├── ThreeRemoveTwoComponents.cs │ │ │ ├── TwoAddOneComponent.cs │ │ │ ├── TwoAddTwoComponents.cs │ │ │ └── TwoRemoveOneComponent.cs │ ├── IBenchmark.cs │ └── Systems │ │ ├── SystemWith1Component.cs │ │ ├── SystemWith2Components.cs │ │ └── SystemWith3Components.cs ├── Constants.cs ├── Options.cs ├── Program.cs └── Utils │ ├── ContextColumn.cs │ └── HashColumn.cs ├── CONTRIBUTING.md ├── FFS.StaticEcs.Workaround └── FFS.StaticEcs.Workaround.csproj ├── LICENSE ├── LeoECS └── LeoECS.csproj ├── LeoECSLite └── LeoECSLite.csproj ├── README.md ├── Raw_Runner ├── Program.cs └── Raw_Runner.csproj └── Scellecs.Morpeh.Workaround ├── Scellecs.Morpeh.Workaround.csproj └── WorldExtensions.cs /.github/workflows/benchmark.yml: -------------------------------------------------------------------------------- 1 | name: Run parallel benchmarks 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | paths: 7 | - './github/workflows/benchmark.yml' 8 | - './github/workflows/test.yml' 9 | - '**.cs' 10 | - '**.csproj' 11 | - '**.sln' 12 | workflow_dispatch: 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | outputs: 18 | matrix: ${{ steps.out.outputs.matrix }} 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 1 23 | submodules: true 24 | - name: Setup .NET 25 | uses: actions/setup-dotnet@v4 26 | with: 27 | dotnet-version: 9.0.x 28 | - name: Restore Benchmark 29 | run: dotnet restore 30 | - name: Build Solution 31 | run: dotnet build -c Release /p:CheckCacheMisses=false 32 | - name: Build Benchmark 33 | run: dotnet publish -c Release /p:CheckCacheMisses=false Benchmark/Benchmark.csproj -o .benchmark 34 | - name: Prepare benchmarks list 35 | run: ./.benchmark/Benchmark --list > benchmarks.txt 36 | - name: Prepare Matrix 37 | id: out 38 | run: | 39 | echo "{\"benchmark\": $(jq --raw-input --slurp --compact-output 'split("\n") | map(select(. != ""))' benchmarks.txt)}" > matrix.json 40 | cat matrix.json 41 | echo "matrix=$(cat matrix.json)" >> $GITHUB_OUTPUT 42 | - name: Archive benchmark build 43 | uses: actions/upload-artifact@v4 44 | with: 45 | name: benchmark 46 | path: .benchmark/ 47 | retention-days: 1 48 | overwrite: 'true' 49 | include-hidden-files: 'true' 50 | 51 | run: 52 | runs-on: ubuntu-latest 53 | needs: build 54 | strategy: 55 | max-parallel: 16 56 | matrix: ${{ fromJson(needs.build.outputs.matrix) }} 57 | steps: 58 | - uses: actions/checkout@v4 59 | with: 60 | fetch-depth: 1 61 | submodules: true 62 | - name: Setup .NET 63 | uses: actions/setup-dotnet@v4 64 | with: 65 | dotnet-version: 9.0.x 66 | - name: Download Benchmark 67 | uses: actions/download-artifact@v4 68 | with: 69 | name: benchmark 70 | path: .benchmark/ 71 | - name: Run Benchmark 72 | run: | 73 | chmod +x ./.benchmark/Benchmark 74 | ./.benchmark/Benchmark benchmark=${{ matrix.benchmark }} 75 | - name: Upload Benchmark Report 76 | uses: actions/upload-artifact@v4 77 | with: 78 | name: benchmark-report-${{ matrix.benchmark }} 79 | path: | 80 | .benchmark_results/${{ matrix.benchmark }}/results/*.md 81 | .benchmark_results/hwinfo 82 | retention-days: 1 83 | 84 | merge-reports: 85 | runs-on: ubuntu-latest 86 | needs: run 87 | steps: 88 | - name: Download Benchmark Reports 89 | uses: actions/download-artifact@v4 90 | with: 91 | merge-multiple: true 92 | path: .benchmark_results/ 93 | - name: Merge Benchmark Reports 94 | run: | 95 | find .benchmark_results/ | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/" 96 | echo -e "# Build from:\n" >> report.md 97 | echo -e "https://github.com/blackbone/other-ecs-benchmarks/commit/$GITHUB_SHA\n" >> report.md 98 | echo -e "HW Info:\n" >> report.md 99 | cat .benchmark_results/hwinfo >> report.md 100 | echo -e "\n" >> report.md 101 | find .benchmark_results -name '*.md' -print0 | while IFS= read -r -d '' file; do 102 | first_line=$(head -n 1 "$file") 103 | echo "$first_line|$file" 104 | done | sort | while IFS='|' read -r first_line file; do 105 | cat "$file" >> report.md 106 | echo -e "\n" >> report.md 107 | done 108 | # upload main report 109 | - name: Update Gist 110 | uses: exuanbo/actions-deploy-gist@v1 111 | with: 112 | token: ${{ secrets.TOKEN }} 113 | gist_id: 6d254a684cf580441bf58690ad9485c3 114 | file_path: report.md 115 | file_type: text 116 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | paths: 7 | - './github/workflows/benchmark.yml' 8 | - './github/workflows/test.yml' 9 | - '**.cs' 10 | - '**.csproj' 11 | - '**.sln' 12 | workflow_dispatch: 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | outputs: 18 | matrix: ${{ steps.out.outputs.matrix }} 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 1 23 | submodules: true 24 | - name: Setup .NET 25 | uses: actions/setup-dotnet@v4 26 | with: 27 | dotnet-version: 9.0.x 28 | - name: Restore Benchmark 29 | run: dotnet restore 30 | - name: Build Benchmark 31 | run: dotnet build -c Release /p:CheckCacheMisses=false 32 | - name: Run Tests 33 | run: dotnet test -c Release -v quiet --nologo -l:"console;verbosity=normal" 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .benchmark_results/ 2 | [Bb]in/ 3 | [Oo]bj/ 4 | .DS_Store 5 | .benchmark_bin 6 | .benchmark 7 | report.md 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "submodules/DragonECS"] 2 | path = submodules/DragonECS 3 | url = git@github.com:DCFApixels/DragonECS.git 4 | [submodule "submodules/morpeh"] 5 | path = submodules/morpeh 6 | url = git@github.com:scellecs/morpeh.git 7 | [submodule "submodules/leopotam-ecs"] 8 | path = submodules/leopotam-ecs 9 | url = git@github.com:Leopotam/ecs.git 10 | [submodule "submodules/leopotam-ecslite"] 11 | path = submodules/leopotam-ecslite 12 | url = git@github.com:Leopotam/ecslite.git 13 | [submodule "submodules/xeno"] 14 | path = submodules/xeno 15 | url = git@github.com:blackbone/xeno.git 16 | [submodule "submodules/StaticEcs"] 17 | path = submodules/StaticEcs 18 | url = git@github.com:Felid-Force-Studios/StaticEcs.git 19 | [submodule "submodules/massive-ecs"] 20 | path = submodules/massive-ecs 21 | url = git@github.com:nilpunch/massive-ecs.git 22 | -------------------------------------------------------------------------------- /.idea/.idea.Benchmark/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /projectSettingsUpdater.xml 6 | /.idea.Benchmark.iml 7 | /modules.xml 8 | /contentModel.xml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /.idea/.idea.Benchmark/.idea/.name: -------------------------------------------------------------------------------- 1 | Benchmark -------------------------------------------------------------------------------- /.idea/.idea.Benchmark/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/.idea.Benchmark/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/.idea.Benchmark/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ArrayECS/ArrayECS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | Array.ECS 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ArrayECS/World.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace AECS { 7 | public abstract class ArraySystem 8 | { 9 | private ArrayWorld _world; 10 | 11 | protected float delta; 12 | 13 | internal ArrayWorld world { 14 | get => _world; 15 | set { 16 | _world = value; 17 | OnWorldInjected(); 18 | } 19 | } 20 | 21 | protected abstract void OnWorldInjected(); 22 | 23 | protected internal abstract void Update(float delta); 24 | } 25 | 26 | public abstract class ArraySystem : ArraySystem { 27 | private T[] data; 28 | private BitArray mask; 29 | 30 | protected sealed override void OnWorldInjected() { 31 | world.GetData(out data, out mask); 32 | } 33 | 34 | protected internal sealed override void Update(float delta) { 35 | this.delta = delta; 36 | for (int i = 0; i < base.world.EntityCount; i++) { 37 | if (mask.Get(i)) 38 | OnUpdate(ref data[i]); 39 | } 40 | } 41 | 42 | protected abstract void OnUpdate(ref T c); 43 | } 44 | 45 | public abstract class ArraySystem : ArraySystem { 46 | private T1[] data1; 47 | private T2[] data2; 48 | private BitArray mask1; 49 | private BitArray mask2; 50 | 51 | private BitArray crossMask; 52 | 53 | protected sealed override void OnWorldInjected() { 54 | world.GetData(out data1, out mask1); 55 | world.GetData(out data2, out mask2); 56 | 57 | crossMask = new BitArray(mask1.Length); 58 | } 59 | 60 | protected internal sealed override void Update(float delta) { 61 | this.delta = delta; 62 | 63 | crossMask.Or(mask1).And(mask2); 64 | for (int i = 0; i < base.world.EntityCount; i++) { 65 | if (crossMask.Get(i)) 66 | OnUpdate(ref data1[i], ref data2[i]); 67 | } 68 | } 69 | 70 | protected abstract void OnUpdate(ref T1 c1, ref T2 c2); 71 | } 72 | 73 | public abstract class ArraySystem : ArraySystem { 74 | private T1[] data1; 75 | private T2[] data2; 76 | private T3[] data3; 77 | private BitArray mask1; 78 | private BitArray mask2; 79 | private BitArray mask3; 80 | 81 | private BitArray crossMask; 82 | 83 | protected sealed override void OnWorldInjected() { 84 | world.GetData(out data1, out mask1); 85 | world.GetData(out data2, out mask2); 86 | world.GetData(out data3, out mask3); 87 | 88 | crossMask = new BitArray(mask1.Length); 89 | } 90 | 91 | protected internal sealed override void Update(float delta) { 92 | this.delta = delta; 93 | 94 | crossMask.Or(mask1).And(mask2).And(mask3); 95 | for (int i = 0; i < base.world.EntityCount; i++) { 96 | if (crossMask.Get(i)) 97 | OnUpdate(ref data1[i], ref data2[i], ref data3[i]); 98 | } 99 | } 100 | 101 | protected abstract void OnUpdate(ref T1 c1, ref T2 c2, ref T3 c3); 102 | } 103 | 104 | public abstract class ArraySystem : ArraySystem { 105 | private T1[] data1; 106 | private T2[] data2; 107 | private T3[] data3; 108 | private T4[] data4; 109 | private BitArray mask1; 110 | private BitArray mask2; 111 | private BitArray mask3; 112 | private BitArray mask4; 113 | 114 | private BitArray crossMask; 115 | 116 | protected sealed override void OnWorldInjected() { 117 | world.GetData(out data1, out mask1); 118 | world.GetData(out data2, out mask2); 119 | world.GetData(out data3, out mask3); 120 | world.GetData(out data4, out mask4); 121 | 122 | crossMask = new BitArray(mask1.Length); 123 | } 124 | 125 | protected internal sealed override void Update(float delta) { 126 | this.delta = delta; 127 | 128 | crossMask.Or(mask1).And(mask2).And(mask3).And(mask4); 129 | for (int i = 0; i < base.world.EntityCount; i++) { 130 | if (crossMask.Get(i)) 131 | OnUpdate(ref data1[i], ref data2[i], ref data3[i], ref data4[i]); 132 | } 133 | } 134 | 135 | protected abstract void OnUpdate(ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4); 136 | } 137 | 138 | public class ArrayWorld : IDisposable { 139 | private const ulong IS_ALIVE_MASK = 0b1000000000000000000000000000000000000000000000000000000000000000L; 140 | private const int ID_SHIFT = 31; 141 | 142 | private ulong[] entities; 143 | private readonly Dictionary components = new Dictionary(); 144 | private readonly List systems = new List(); 145 | 146 | public int EntityCount { get; private set; } 147 | 148 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 149 | public ArrayWorld(int entityCount) { 150 | entities = new ulong[entityCount]; 151 | InitEntities(0, entityCount); 152 | EntityCount = 0; 153 | } 154 | 155 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 156 | private void InitEntities(int min, int max) { 157 | while (min < max) { 158 | entities[min] = ~IS_ALIVE_MASK & ((ulong)min << ID_SHIFT); 159 | min++; 160 | } 161 | } 162 | 163 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 164 | public ulong CreateEntity() { 165 | if (EntityCount == entities.Length) { 166 | throw new IndexOutOfRangeException(); 167 | } 168 | 169 | entities[EntityCount] |= IS_ALIVE_MASK; 170 | return entities[EntityCount++]; 171 | } 172 | 173 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 174 | public void DestroyEntity(ulong e) { 175 | var idx = getIdx(e); 176 | if (e != entities[idx]) return; 177 | entities[idx] = ++e & ~IS_ALIVE_MASK; 178 | EntityCount--; 179 | } 180 | 181 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 182 | public void AddComponent(in ulong e, in T c1) { 183 | var idx = getIdx(e); 184 | if (e != entities[idx]) return; 185 | GetData(out T[] data, out var mask); 186 | data[idx] = c1; 187 | mask.Set((int)idx, true); 188 | } 189 | 190 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 191 | public void RemoveComponent(in ulong e) { 192 | var idx = getIdx(e); 193 | if (e != entities[idx]) return; 194 | GetData(out T[] data, out var mask); 195 | data[idx] = default; 196 | mask.Set((int)idx, false); 197 | } 198 | 199 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 200 | public int Count() { 201 | if (!components.TryGetValue(typeof(T1), out var data1)) return 0; 202 | return data1.mask.Count; 203 | } 204 | 205 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 206 | public int Count() { 207 | if (!components.TryGetValue(typeof(T1), out var data1)) return 0; 208 | if (!components.TryGetValue(typeof(T2), out var data2)) return 0; 209 | 210 | return new BitArray(data1.mask).And(data2.mask).Count; 211 | } 212 | 213 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 214 | public int Count() { 215 | if (!components.TryGetValue(typeof(T1), out var data1)) return 0; 216 | if (!components.TryGetValue(typeof(T2), out var data2)) return 0; 217 | if (!components.TryGetValue(typeof(T3), out var data3)) return 0; 218 | 219 | return new BitArray(data1.mask).And(data2.mask).And(data3.mask).Count; 220 | } 221 | 222 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 223 | public int Count() { 224 | if (!components.TryGetValue(typeof(T1), out var data1)) return 0; 225 | if (!components.TryGetValue(typeof(T2), out var data2)) return 0; 226 | if (!components.TryGetValue(typeof(T3), out var data3)) return 0; 227 | if (!components.TryGetValue(typeof(T4), out var data4)) return 0; 228 | 229 | return new BitArray(data1.mask).And(data2.mask).And(data3.mask).And(data4.mask).Count; 230 | } 231 | 232 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 233 | public T Get(in ulong e) { 234 | var idx = getIdx(e); 235 | if (e != entities[idx]) return default; 236 | 237 | return !components.TryGetValue(typeof(T), out var data) ? default : ((Data)data).Get(idx); 238 | } 239 | 240 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 241 | public bool Ref(in ulong e, ref T c) { 242 | var idx = getIdx(e); 243 | if (e != entities[idx]) return false; 244 | 245 | return components.TryGetValue(typeof(T), out var data) && ((Data)data).Ref(idx, ref c); 246 | } 247 | 248 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 249 | public void Dispose() { 250 | entities = null; 251 | } 252 | 253 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 254 | public void Preallocate(int entityCount) { 255 | components[typeof(T)] = new Data(entityCount); 256 | } 257 | 258 | 259 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 260 | private static uint getIdx(ulong entityId) => (uint)((entityId & ~IS_ALIVE_MASK) >> ID_SHIFT); 261 | 262 | private class Data { 263 | public readonly BitArray mask; 264 | protected Data(int count) => mask = new BitArray(count); 265 | } 266 | 267 | private class Data : Data { 268 | internal readonly T[] data; 269 | 270 | public Data(int count):base(count) => data = new T[count]; 271 | 272 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 273 | public void Add(in uint idx, in T c) { 274 | if (mask.Get((int)idx)) return; 275 | if (idx >= data.Length) throw new IndexOutOfRangeException(); 276 | data[idx] = c; 277 | } 278 | 279 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 280 | public void Remove(in uint idx) { 281 | if (idx >= data.Length) return; 282 | if (!mask.Get((int)idx)) return; 283 | data[idx] = default; 284 | } 285 | 286 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 287 | public T Get(in uint idx) { 288 | if (idx >= data.Length) return default; 289 | if (!mask.Get((int)idx)) return default; 290 | return data[idx]; 291 | } 292 | 293 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 294 | public bool Ref(in uint idx, ref T c) { 295 | if (idx >= data.Length) return false; 296 | if (!mask.Get((int)idx)) return false; 297 | c = ref data[idx]; 298 | return true; 299 | } 300 | } 301 | 302 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 303 | public void Update(float delta) { 304 | foreach (var system in systems) 305 | system.Update(delta); 306 | } 307 | 308 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 309 | public void AddSystem(ArraySystem system) { 310 | system.world = this; 311 | systems.Add(system); 312 | } 313 | 314 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 315 | internal void GetData(out T[] data, out BitArray mask) { 316 | Data dataWrapper; 317 | if (!components.TryGetValue(typeof(T), out var d)) 318 | components[typeof(T)] = dataWrapper = new Data(entities.Length); 319 | else 320 | dataWrapper = (Data)d; 321 | 322 | data = dataWrapper.data; 323 | mask = dataWrapper.mask; 324 | } 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /Benchmark.Arch/Benchmark.Arch.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Benchmark.Arch/System.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Arch.Core; 3 | 4 | namespace Benchmark.Arch; 5 | 6 | public unsafe class System(delegate* method) 7 | { 8 | private readonly struct ForEach(delegate* method) : IForEach 9 | { 10 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 11 | public void Update(ref T t0) => method(ref t0); 12 | } 13 | 14 | private ForEach _forEach = new(method); 15 | private readonly QueryDescription _query = new([typeof(T)]); 16 | 17 | public void ForEachQuery(World world) => world.InlineQuery(_query, ref _forEach); 18 | } 19 | 20 | public unsafe class System(delegate* method) 21 | { 22 | private readonly struct ForEach(delegate* method) : IForEach 23 | { 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public void Update(ref T1 t1, ref T2 t2) => method(ref t1, ref t2); 26 | } 27 | 28 | private ForEach _forEach = new(method); 29 | private readonly QueryDescription _query = new([typeof(T1), typeof(T2)]); 30 | 31 | public void ForEachQuery(World world) => world.InlineQuery(_query, ref _forEach); 32 | } 33 | 34 | public unsafe class System(delegate* method) 35 | { 36 | private readonly struct ForEach(delegate* method) : IForEach 37 | { 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | public void Update(ref T1 t1, ref T2 t2, ref T3 t3) => method(ref t1, ref t2, ref t3); 40 | } 41 | 42 | private ForEach _forEach = new(method); 43 | 44 | private readonly QueryDescription _query = new([typeof(T1), typeof(T2), typeof(T3)]); 45 | 46 | public void ForEachQuery(World world) => world.InlineQuery(_query, ref _forEach); 47 | } 48 | 49 | public unsafe class System(delegate* method) 50 | { 51 | private readonly struct ForEach(delegate* method) : IForEach 52 | { 53 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 54 | public void Update(ref T1 t1, ref T2 t2, ref T3 t3, ref T4 t4) => method(ref t1, ref t2, ref t3, ref t4); 55 | } 56 | 57 | private ForEach _forEach = new(method); 58 | 59 | private readonly QueryDescription _query = new([typeof(T1), typeof(T2), typeof(T3), typeof(T4)]); 60 | 61 | public void ForEachQuery(World world) => world.InlineQuery(_query, ref _forEach); 62 | } -------------------------------------------------------------------------------- /Benchmark.ArrayECS/Benchmark.ArrayECS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | enable 6 | disable 7 | 8 | 9 | 10 | true 11 | 12 | 13 | 14 | true 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Benchmark.DefaultECS/Benchmark.DefaultECS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Benchmark.DefaultECS/System.cs: -------------------------------------------------------------------------------- 1 | using DefaultEcs; 2 | using DefaultEcs.System; 3 | 4 | namespace Benchmark.DefaultECS; 5 | 6 | public sealed unsafe class System(EntityQueryBuilder query, delegate* method) : ISystem 7 | { 8 | public bool IsEnabled { get; set; } = true; 9 | public void Dispose() { } 10 | 11 | public void Update(float state) 12 | { 13 | foreach (var entity in query.AsEnumerable()) 14 | method(ref entity.Get()); 15 | } 16 | } 17 | 18 | public sealed unsafe class System(EntityQueryBuilder query, delegate* method) : ISystem 19 | { 20 | public bool IsEnabled { get; set; } = true; 21 | public void Dispose() { } 22 | 23 | public void Update(float state) 24 | { 25 | foreach (var entity in query.AsEnumerable()) 26 | method(ref entity.Get(), ref entity.Get()); 27 | } 28 | } 29 | 30 | public sealed unsafe class System(EntityQueryBuilder query, delegate* method) : ISystem 31 | { 32 | public bool IsEnabled { get; set; } = true; 33 | public void Dispose() { } 34 | 35 | public void Update(float state) 36 | { 37 | foreach (var entity in query.AsEnumerable()) 38 | method(ref entity.Get(), ref entity.Get(), ref entity.Get()); 39 | } 40 | } 41 | 42 | public sealed unsafe class System(EntityQueryBuilder query, delegate* method) : ISystem 43 | { 44 | public bool IsEnabled { get; set; } = true; 45 | public void Dispose() { } 46 | 47 | public void Update(float state) 48 | { 49 | foreach (var entity in query.AsEnumerable()) 50 | method(ref entity.Get(), ref entity.Get(), ref entity.Get(), ref entity.Get()); 51 | } 52 | } -------------------------------------------------------------------------------- /Benchmark.DragonECS/Benchmark.DragonECS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Benchmark.DragonECS/GenericAspects.cs: -------------------------------------------------------------------------------- 1 | using DCFApixels.DragonECS; 2 | 3 | namespace Benchmark.DragonECS; 4 | 5 | public class Aspect : EcsAspect 6 | where T1 : struct, IEcsComponent 7 | { 8 | public EcsPool Components1; 9 | 10 | protected override void Init(Builder b) 11 | { 12 | base.Init(b); 13 | Components1 = b.Inc(); 14 | } 15 | } 16 | 17 | public class Aspect : EcsAspect 18 | where T1 : struct, IEcsComponent 19 | where T2 : struct, IEcsComponent 20 | { 21 | public EcsPool Components1; 22 | public EcsPool Components2; 23 | 24 | protected override void Init(Builder b) 25 | { 26 | base.Init(b); 27 | Components1 = b.Inc(); 28 | Components2 = b.Inc(); 29 | } 30 | } 31 | 32 | public class Aspect : EcsAspect 33 | where T1 : struct, IEcsComponent 34 | where T2 : struct, IEcsComponent 35 | where T3 : struct, IEcsComponent 36 | { 37 | public EcsPool Components1; 38 | public EcsPool Components2; 39 | public EcsPool Components3; 40 | 41 | protected override void Init(Builder b) 42 | { 43 | base.Init(b); 44 | Components1 = b.Inc(); 45 | Components2 = b.Inc(); 46 | Components3 = b.Inc(); 47 | } 48 | } 49 | 50 | public class Aspect : EcsAspect 51 | where T1 : struct, IEcsComponent 52 | where T2 : struct, IEcsComponent 53 | where T3 : struct, IEcsComponent 54 | where T4 : struct, IEcsComponent 55 | { 56 | public EcsPool Components1; 57 | public EcsPool Components2; 58 | public EcsPool Components3; 59 | public EcsPool Components4; 60 | 61 | protected override void Init(Builder b) 62 | { 63 | base.Init(b); 64 | Components1 = b.Inc(); 65 | Components2 = b.Inc(); 66 | Components3 = b.Inc(); 67 | Components4 = b.Inc(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Benchmark.DragonECS/PointerInvocationSystem.cs: -------------------------------------------------------------------------------- 1 | using DCFApixels.DragonECS; 2 | 3 | namespace Benchmark.DragonECS; 4 | 5 | public class PointerInvocationSystem : IEcsRun 6 | where T1 : struct, IEcsComponent 7 | { 8 | private readonly unsafe delegate* _method; 9 | private readonly EcsWorld _world; 10 | private readonly Aspect _aspect; 11 | 12 | public unsafe PointerInvocationSystem(EcsWorld world, delegate* method) 13 | { 14 | _world = world; 15 | _method = method; 16 | _aspect = _world.GetAspect>(); 17 | } 18 | 19 | public unsafe void Run() 20 | { 21 | foreach (var e in _world.Where(_aspect)) 22 | _method(ref _aspect.Components1.Get(e)); 23 | } 24 | } 25 | 26 | public class PointerInvocationSystem : IEcsRun 27 | where T1 : struct, IEcsComponent 28 | where T2 : struct, IEcsComponent 29 | { 30 | private readonly unsafe delegate* _method; 31 | private readonly EcsWorld _world; 32 | private readonly Aspect _aspect; 33 | 34 | public unsafe PointerInvocationSystem(EcsWorld world, delegate* method) 35 | { 36 | _world = world; 37 | _method = method; 38 | _aspect = _world.GetAspect>(); 39 | } 40 | 41 | public unsafe void Run() 42 | { 43 | foreach (var e in _world.Where(_aspect)) 44 | _method(ref _aspect.Components1.Get(e), ref _aspect.Components2.Get(e)); 45 | } 46 | } 47 | 48 | public class PointerInvocationSystem : IEcsRun 49 | where T1 : struct, IEcsComponent 50 | where T2 : struct, IEcsComponent 51 | where T3 : struct, IEcsComponent 52 | { 53 | private readonly unsafe delegate* _method; 54 | private readonly EcsWorld _world; 55 | private readonly Aspect _aspect; 56 | 57 | public unsafe PointerInvocationSystem(EcsWorld world, delegate* method) 58 | { 59 | _world = world; 60 | _method = method; 61 | _aspect = _world.GetAspect>(); 62 | } 63 | 64 | public unsafe void Run() 65 | { 66 | foreach (var e in _world.Where(_aspect)) 67 | _method(ref _aspect.Components1.Get(e), ref _aspect.Components2.Get(e), ref _aspect.Components3.Get(e)); 68 | } 69 | } 70 | 71 | public class PointerInvocationSystem : IEcsRun 72 | where T1 : struct, IEcsComponent 73 | where T2 : struct, IEcsComponent 74 | where T3 : struct, IEcsComponent 75 | where T4 : struct, IEcsComponent 76 | { 77 | private readonly unsafe delegate* _method; 78 | private readonly EcsWorld _world; 79 | private readonly Aspect _aspect; 80 | 81 | public unsafe PointerInvocationSystem(EcsWorld world, delegate* method) 82 | { 83 | _world = world; 84 | _method = method; 85 | _aspect = _world.GetAspect>(); 86 | } 87 | 88 | public unsafe void Run() 89 | { 90 | foreach (var e in _world.Where(_aspect)) 91 | _method(ref _aspect.Components1.Get(e), ref _aspect.Components2.Get(e), ref _aspect.Components3.Get(e), ref _aspect.Components4.Get(e)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Benchmark.Fennecs/Benchmark.Fennecs.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Benchmark.Fennecs/System.cs: -------------------------------------------------------------------------------- 1 | using fennecs; 2 | 3 | #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value 4 | 5 | namespace Benchmark.Fennecs; 6 | 7 | public interface ISystem 8 | { 9 | void Run(float delta); 10 | } 11 | 12 | public unsafe class System : ISystem 13 | where T1 : struct 14 | { 15 | private readonly ComponentAction _del; 16 | private readonly delegate* _method; 17 | private readonly Stream _stream; 18 | 19 | public System(delegate* method, Stream stream) 20 | { 21 | _del = Invoke; 22 | _method = method; 23 | _stream = stream; 24 | } 25 | 26 | public void Run(float delta) 27 | { 28 | _stream.Job(_del); 29 | } 30 | 31 | private void Invoke(ref T1 c0) 32 | { 33 | _method(ref c0); 34 | } 35 | } 36 | 37 | public unsafe class System : ISystem 38 | where T1 : struct 39 | where T2 : struct 40 | { 41 | private readonly ComponentAction _del; 42 | private readonly delegate* _method; 43 | private readonly Stream _stream; 44 | 45 | public System(delegate* method, Stream stream) 46 | { 47 | _del = Invoke; 48 | _method = method; 49 | _stream = stream; 50 | } 51 | 52 | public void Run(float delta) 53 | { 54 | _stream.Job(_del); 55 | } 56 | 57 | private void Invoke(ref T1 c0, ref T2 c1) 58 | { 59 | _method(ref c0, ref c1); 60 | } 61 | } 62 | 63 | public unsafe class System : ISystem 64 | where T1 : struct 65 | where T2 : struct 66 | where T3 : struct 67 | { 68 | private readonly ComponentAction _del; 69 | private readonly delegate* _method; 70 | private readonly Stream _stream; 71 | 72 | public System(delegate* method, Stream stream) 73 | { 74 | _del = Invoke; 75 | _method = method; 76 | _stream = stream; 77 | } 78 | 79 | public void Run(float delta) 80 | { 81 | _stream.Job(_del); 82 | } 83 | 84 | private void Invoke(ref T1 c0, ref T2 c1, ref T3 c2) 85 | { 86 | _method(ref c0, ref c1, ref c2); 87 | } 88 | } 89 | 90 | public unsafe class System : ISystem 91 | where T1 : struct 92 | where T2 : struct 93 | where T3 : struct 94 | where T4 : struct 95 | { 96 | private readonly ComponentAction _del; 97 | private readonly delegate* _method; 98 | private readonly Stream _stream; 99 | 100 | public System(delegate* method, Stream stream) 101 | { 102 | _del = Invoke; 103 | _method = method; 104 | _stream = stream; 105 | } 106 | 107 | public void Run(float delta) 108 | { 109 | _stream.Job(_del); 110 | } 111 | 112 | private void Invoke(ref T1 c0, ref T2 c1, ref T3 c2, ref T4 c3) 113 | { 114 | _method(ref c0, ref c1, ref c2, ref c3); 115 | } 116 | } -------------------------------------------------------------------------------- /Benchmark.FlecsNET/Benchmark.FlecsNET.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Benchmark.FriFlo/Benchmark.FriFlo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Benchmark.FriFlo/FriFloSystem.cs: -------------------------------------------------------------------------------- 1 | using Friflo.Engine.ECS; 2 | using Friflo.Engine.ECS.Systems; 3 | 4 | namespace Benchmark.FriFlo; 5 | 6 | public unsafe class FriFloSystem(delegate* method) : QuerySystem 7 | where T1 : struct, IComponent 8 | { 9 | protected override void OnUpdate() 10 | { 11 | var job = Query.ForEach(Job); 12 | job.Run(); 13 | } 14 | 15 | private void Job(Chunk c1, ChunkEntities entities) 16 | { 17 | for (var i = 0; i < c1.Length; i++) { 18 | method(ref c1[i]); 19 | } 20 | } 21 | } 22 | 23 | public unsafe class FriFloSystem(delegate* method) : QuerySystem 24 | where T1 : struct, IComponent 25 | where T2 : struct, IComponent 26 | { 27 | protected override void OnUpdate() 28 | { 29 | var job = Query.ForEach(Job); 30 | job.Run(); 31 | } 32 | 33 | private void Job(Chunk c1, Chunk c2, ChunkEntities entities) 34 | { 35 | for (var i = 0; i < entities.Length; i++) { 36 | method(ref c1[i], ref c2[i]); 37 | } 38 | } 39 | } 40 | 41 | public unsafe class FriFloSystem(delegate* method) : QuerySystem 42 | where T1 : struct, IComponent 43 | where T2 : struct, IComponent 44 | where T3 : struct, IComponent 45 | { 46 | protected override void OnUpdate() 47 | { 48 | var job = Query.ForEach(Job); 49 | job.Run(); 50 | } 51 | 52 | private void Job(Chunk c1, Chunk c2, Chunk c3, ChunkEntities entities) 53 | { 54 | for (var i = 0; i < entities.Length; i++) { 55 | method(ref c1[i], ref c2[i], ref c3[i]); 56 | } 57 | } 58 | } 59 | 60 | public unsafe class FriFloSystem(delegate* method) : QuerySystem 61 | where T1 : struct, IComponent 62 | where T2 : struct, IComponent 63 | where T3 : struct, IComponent 64 | where T4 : struct, IComponent 65 | { 66 | protected override void OnUpdate() 67 | { 68 | var job = Query.ForEach(Job); 69 | job.Run(); 70 | } 71 | 72 | private void Job(Chunk c1, Chunk c2, Chunk c3, Chunk c4, ChunkEntities entities) 73 | { 74 | for (var i = 0; i < entities.Length; i++) { 75 | method(ref c1[i], ref c2[i], ref c3[i], ref c4[i]); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /Benchmark.LeoEcs/Benchmark.LeoEcs.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Benchmark.LeoEcs/System.cs: -------------------------------------------------------------------------------- 1 | using Leopotam.Ecs; 2 | 3 | #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value 4 | 5 | namespace Benchmark.LeoEcs; 6 | 7 | public unsafe class System(delegate* method) : IEcsRunSystem 8 | where T1 : struct 9 | { 10 | private readonly EcsFilter _filter; 11 | 12 | public void Run() 13 | { 14 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++) 15 | method(ref _filter.Get1(i)); 16 | } 17 | } 18 | 19 | public unsafe class System(delegate* method) : IEcsRunSystem 20 | where T1 : struct 21 | where T2 : struct 22 | { 23 | private readonly EcsFilter _filter; 24 | 25 | public void Run() 26 | { 27 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++) 28 | method(ref _filter.Get1(i), ref _filter.Get2(i)); 29 | } 30 | } 31 | 32 | public unsafe class System(delegate* method) : IEcsRunSystem 33 | where T1 : struct 34 | where T2 : struct 35 | where T3 : struct 36 | { 37 | private readonly EcsFilter _filter; 38 | 39 | public void Run() 40 | { 41 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++) 42 | method(ref _filter.Get1(i), ref _filter.Get2(i), ref _filter.Get3(i)); 43 | } 44 | } 45 | 46 | public unsafe class System(delegate* method) : IEcsRunSystem 47 | where T1 : struct 48 | where T2 : struct 49 | where T3 : struct 50 | where T4 : struct 51 | { 52 | private readonly EcsFilter _filter; 53 | 54 | public void Run() 55 | { 56 | for (int i = 0, iMax = _filter.GetEntitiesCount(); i < iMax; i++) 57 | method(ref _filter.Get1(i), ref _filter.Get2(i), ref _filter.Get3(i), ref _filter.Get4(i)); 58 | } 59 | } -------------------------------------------------------------------------------- /Benchmark.LeoEcsLite/Benchmark.LeoEcsLite.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Benchmark.LeoEcsLite/System.cs: -------------------------------------------------------------------------------- 1 | using Leopotam.EcsLite; 2 | 3 | #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value 4 | 5 | namespace Benchmark.LeoEcsLite; 6 | 7 | public unsafe class System(delegate* method) : IEcsInitSystem, IEcsRunSystem 8 | where T1 : struct 9 | { 10 | private EcsFilter _filter; 11 | private EcsPool _p1; 12 | 13 | public void Init(IEcsSystems systems) 14 | { 15 | var world = systems.GetWorld(); 16 | _filter = world.Filter().End(); 17 | _p1 = world.GetPool(); 18 | } 19 | 20 | public void Run(IEcsSystems systems) 21 | { 22 | foreach (var entity in _filter!) 23 | method(ref _p1!.Get(entity)); 24 | } 25 | } 26 | 27 | public unsafe class System(delegate* method) : IEcsInitSystem, IEcsRunSystem 28 | where T1 : struct 29 | where T2 : struct 30 | { 31 | private EcsFilter _filter; 32 | private EcsPool _p1; 33 | private EcsPool _p2; 34 | 35 | public void Init(IEcsSystems systems) 36 | { 37 | var world = systems.GetWorld(); 38 | _filter = world.Filter().End(); 39 | _p1 = world.GetPool(); 40 | _p2 = world.GetPool(); 41 | } 42 | 43 | public void Run(IEcsSystems systems) 44 | { 45 | foreach (var entity in _filter!) 46 | method(ref _p1!.Get(entity), ref _p2!.Get(entity)); 47 | } 48 | } 49 | 50 | public unsafe class System(delegate* method) : IEcsInitSystem, IEcsRunSystem 51 | where T1 : struct 52 | where T2 : struct 53 | where T3 : struct 54 | { 55 | private EcsFilter _filter; 56 | private EcsPool _p1; 57 | private EcsPool _p2; 58 | private EcsPool _p3; 59 | 60 | public void Init(IEcsSystems systems) 61 | { 62 | var world = systems.GetWorld(); 63 | _filter = world.Filter().End(); 64 | _p1 = world.GetPool(); 65 | _p2 = world.GetPool(); 66 | _p3 = world.GetPool(); 67 | } 68 | 69 | public void Run(IEcsSystems systems) 70 | { 71 | foreach (var entity in _filter!) 72 | method(ref _p1!.Get(entity), ref _p2!.Get(entity), ref _p3!.Get(entity)); 73 | } 74 | } 75 | 76 | public unsafe class System(delegate* method) 77 | : IEcsInitSystem, IEcsRunSystem 78 | where T1 : struct 79 | where T2 : struct 80 | where T3 : struct 81 | where T4 : struct 82 | { 83 | private EcsFilter _filter; 84 | private EcsPool _p1; 85 | private EcsPool _p2; 86 | private EcsPool _p3; 87 | private EcsPool _p4; 88 | 89 | public void Init(IEcsSystems systems) 90 | { 91 | var world = systems.GetWorld(); 92 | _filter = world.Filter().End(); 93 | _p1 = world.GetPool(); 94 | _p2 = world.GetPool(); 95 | _p3 = world.GetPool(); 96 | _p4 = world.GetPool(); 97 | } 98 | 99 | public void Run(IEcsSystems systems) 100 | { 101 | foreach (var entity in _filter!) 102 | method(ref _p1!.Get(entity), ref _p2!.Get(entity), ref _p3!.Get(entity), ref _p4!.Get(entity)); 103 | } 104 | } -------------------------------------------------------------------------------- /Benchmark.MassiveECS/Benchmark.MassiveECS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Benchmark.Morpeh/Benchmark.Morpeh.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Benchmark.Morpeh/PointerInvocationStashSystem.cs: -------------------------------------------------------------------------------- 1 | using Scellecs.Morpeh; 2 | 3 | namespace Benchmark.Morpeh; 4 | 5 | public class PointerInvocationStashSystem : ISystem 6 | where T1 : struct, IComponent 7 | { 8 | private readonly unsafe delegate* _method; 9 | private Filter _filter; 10 | private Stash _stash1; 11 | 12 | #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 13 | public unsafe PointerInvocationStashSystem(delegate* method) 14 | { 15 | _method = method; 16 | } 17 | #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 18 | 19 | public World World { get; set; } 20 | 21 | public void OnAwake() 22 | { 23 | _stash1 = World.GetStash(); 24 | _filter = World.Filter.With().Build(); 25 | } 26 | 27 | public void Dispose() 28 | { 29 | } 30 | 31 | public unsafe void OnUpdate(float delta) 32 | { 33 | foreach (var entity in _filter) 34 | _method(ref _stash1.Get(entity)); 35 | } 36 | } 37 | 38 | public class PointerInvocationStashSystem : ISystem 39 | where T1 : struct, IComponent 40 | where T2 : struct, IComponent 41 | { 42 | private readonly unsafe delegate* _method; 43 | private Filter _filter; 44 | private Stash _stash1; 45 | private Stash _stash2; 46 | 47 | #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 48 | public unsafe PointerInvocationStashSystem(delegate* method) 49 | { 50 | _method = method; 51 | } 52 | #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 53 | 54 | public World World { get; set; } 55 | 56 | public void OnAwake() 57 | { 58 | _stash1 = World.GetStash(); 59 | _stash2 = World.GetStash(); 60 | _filter = World.Filter.With().With().Build(); 61 | } 62 | 63 | public void Dispose() 64 | { 65 | } 66 | 67 | public unsafe void OnUpdate(float delta) 68 | { 69 | foreach (var entity in _filter) 70 | _method(ref _stash1.Get(entity), ref _stash2.Get(entity)); 71 | } 72 | } 73 | 74 | public class PointerInvocationStashSystem : ISystem 75 | where T1 : struct, IComponent 76 | where T2 : struct, IComponent 77 | where T3 : struct, IComponent 78 | { 79 | private readonly unsafe delegate* _method; 80 | private Filter _filter; 81 | private Stash _stash1; 82 | private Stash _stash2; 83 | private Stash _stash3; 84 | 85 | #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 86 | public unsafe PointerInvocationStashSystem(delegate* method) 87 | { 88 | _method = method; 89 | } 90 | #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 91 | 92 | public World World { get; set; } 93 | 94 | public unsafe void OnUpdate(float deltaTime) 95 | { 96 | foreach (var entity in _filter) 97 | _method(ref _stash1.Get(entity), ref _stash2.Get(entity), ref _stash3.Get(entity)); 98 | } 99 | 100 | public void Dispose() 101 | { 102 | } 103 | 104 | public void OnAwake() 105 | { 106 | _stash1 = World.GetStash(); 107 | _stash2 = World.GetStash(); 108 | _stash3 = World.GetStash(); 109 | _filter = World.Filter.With().With().With().Build(); 110 | } 111 | } 112 | 113 | public class PointerInvocationStashSystem : ISystem 114 | where T1 : struct, IComponent 115 | where T2 : struct, IComponent 116 | where T3 : struct, IComponent 117 | where T4 : struct, IComponent 118 | { 119 | private readonly unsafe delegate* _method; 120 | private Filter _filter; 121 | private Stash _stash1; 122 | private Stash _stash2; 123 | private Stash _stash3; 124 | private Stash _stash4; 125 | 126 | #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 127 | public unsafe PointerInvocationStashSystem(delegate* method) 128 | { 129 | _method = method; 130 | } 131 | #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 132 | 133 | public World World { get; set; } 134 | 135 | public void OnAwake() 136 | { 137 | _stash1 = World.GetStash(); 138 | _stash2 = World.GetStash(); 139 | _stash3 = World.GetStash(); 140 | _stash4 = World.GetStash(); 141 | _filter = World.Filter.With().With().With().With().Build(); 142 | } 143 | 144 | public void Dispose() 145 | { 146 | } 147 | 148 | public unsafe void OnUpdate(float deltaTime) 149 | { 150 | foreach (var entity in _filter) 151 | _method(ref _stash1.Get(entity), ref _stash2.Get(entity), ref _stash3.Get(entity), ref _stash4.Get(entity)); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Benchmark.StaticEcs/Benchmark.StaticEcs.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | disable 6 | enable 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Benchmark.TinyECS/Benchmark.TinyECS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 13 6 | disable 7 | disable 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Benchmark.TinyECS/TinyEcsContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using DCFApixels.DragonECS; 4 | using TinyEcs; 5 | using IComponent = Scellecs.Morpeh.IComponent; 6 | 7 | namespace Benchmark.TinyECS; 8 | 9 | public sealed class TinyEcsContext : IBenchmarkContext 10 | { 11 | private TinyEcs.World _world; 12 | private Scheduler _scheduler; 13 | 14 | public bool DeletesEntityOnLastComponentDeletion => false; 15 | public int NumberOfLivingEntities { get; private set; } 16 | 17 | public void Setup() { 18 | _world = new TinyEcs.World(); 19 | _scheduler = new Scheduler(_world); 20 | } 21 | 22 | public void FinishSetup() {} 23 | 24 | public void Warmup(in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent {} 25 | 26 | public void Warmup(in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent {} 27 | public void Warmup(in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent {} 28 | public void Warmup(in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T4 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent {} 29 | public void Cleanup() {} 30 | public void Dispose() 31 | { 32 | _scheduler = null; 33 | 34 | _world.Dispose(); 35 | _world = null; 36 | } 37 | 38 | public void DeleteEntities(in EntityView[] entities) 39 | { 40 | for (var i = 0; i < entities.Length; i++) 41 | if (entities[i] != default) 42 | entities[i].Delete(); 43 | 44 | NumberOfLivingEntities -= entities.Length; 45 | _world.BeginDeferred(); 46 | } 47 | 48 | public EntityView[] PrepareSet(in int count) => new EntityView[count]; 49 | 50 | public void CreateEntities(in EntityView[] entities) 51 | { 52 | for (var i = 0; i < entities.Length; i++) 53 | entities[i] = _world.Entity(); 54 | 55 | NumberOfLivingEntities += entities.Length; 56 | } 57 | 58 | public void CreateEntities(in EntityView[] entities, in int poolId, in T1 c1) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 59 | { 60 | for (var i = 0; i < entities.Length; i++) 61 | entities[i] = _world.Entity().Set(c1); 62 | 63 | NumberOfLivingEntities += entities.Length; 64 | } 65 | 66 | public void CreateEntities(in EntityView[] entities, in int poolId, in T1 c1, in T2 c2) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 67 | { 68 | for (var i = 0; i < entities.Length; i++) 69 | entities[i] = _world.Entity().Set(c1).Set(c2); 70 | 71 | NumberOfLivingEntities += entities.Length; 72 | } 73 | 74 | public void CreateEntities(in EntityView[] entities, in int poolId, in T1 c1, in T2 c2, 75 | in T3 c3) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 76 | { 77 | for (var i = 0; i < entities.Length; i++) 78 | entities[i] = _world.Entity().Set(c1).Set(c2).Set(c3); 79 | 80 | NumberOfLivingEntities += entities.Length; 81 | } 82 | 83 | public void CreateEntities(in EntityView[] entities, in int poolId, in T1 c1, in T2 c2, 84 | in T3 c3, in T4 c4) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T4 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 85 | { 86 | for (var i = 0; i < entities.Length; i++) 87 | entities[i] = _world.Entity().Set(c1).Set(c2).Set(c3).Set(c4); 88 | 89 | NumberOfLivingEntities += entities.Length; 90 | } 91 | 92 | public void AddComponent(in EntityView[] entities, in int poolId, in T1 c1) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 93 | { 94 | for (var i = 0; i < entities.Length; i++) 95 | entities[i].Set(c1); 96 | } 97 | 98 | public void AddComponent(in EntityView[] entities, in int poolId, in T1 c1, in T2 c2) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 99 | { 100 | for (var i = 0; i < entities.Length; i++) 101 | entities[i].Set(c1).Set(c2); 102 | } 103 | 104 | public void AddComponent(in EntityView[] entities, in int poolId, in T1 c1, in T2 c2, 105 | in T3 c3) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 106 | { 107 | for (var i = 0; i < entities.Length; i++) 108 | entities[i].Set(c1).Set(c2).Set(c3); 109 | } 110 | 111 | public void AddComponent(in EntityView[] entities, in int poolId, in T1 c1, in T2 c2, 112 | in T3 c3, in T4 c4) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T4 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 113 | { 114 | for (var i = 0; i < entities.Length; i++) 115 | entities[i].Set(c1).Set(c2).Set(c3).Set(c4); 116 | } 117 | 118 | public void RemoveComponent(in EntityView[] entities, in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 119 | { 120 | for (var i = 0; i < entities.Length; i++) 121 | entities[i].Unset(); 122 | } 123 | 124 | public void RemoveComponent(in EntityView[] entities, in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 125 | { 126 | for (var i = 0; i < entities.Length; i++) 127 | entities[i].Unset().Unset(); 128 | } 129 | 130 | public void RemoveComponent(in EntityView[] entities, in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 131 | { 132 | for (var i = 0; i < entities.Length; i++) 133 | entities[i].Unset().Unset().Unset(); 134 | } 135 | 136 | public void RemoveComponent(in EntityView[] entities, in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T4 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 137 | { 138 | for (var i = 0; i < entities.Length; i++) 139 | entities[i].Unset().Unset().Unset().Unset(); 140 | } 141 | 142 | public int CountWith(in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 143 | => _world.QueryBuilder().With().Build().Count(); 144 | 145 | public int CountWith(in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 146 | => _world.QueryBuilder().With().With().Build().Count(); 147 | 148 | public int CountWith(in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 149 | => _world.QueryBuilder().With().With().With().Build().Count(); 150 | 151 | public int CountWith(in int poolId) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T4 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 152 | => _world.QueryBuilder().With().With().With().With().Build().Count(); 153 | 154 | public bool GetSingle(in EntityView e, in int poolId, ref T1 c1) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 155 | { 156 | c1 = e.Get(); 157 | return true; 158 | } 159 | 160 | public bool GetSingle(in EntityView e, in int poolId, ref T1 c1, ref T2 c2) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 161 | { 162 | c1 = e.Get(); 163 | c2 = e.Get(); 164 | return true; 165 | } 166 | 167 | public bool GetSingle(in EntityView e, in int poolId, ref T1 c1, ref T2 c2, ref T3 c3) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 168 | { 169 | c1 = e.Get(); 170 | c2 = e.Get(); 171 | c3 = e.Get(); 172 | return true; 173 | } 174 | 175 | public bool GetSingle(in EntityView e, in int poolId, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4) where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent where T4 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 176 | { 177 | c1 = e.Get(); 178 | c2 = e.Get(); 179 | c3 = e.Get(); 180 | c4 = e.Get(); 181 | return true; 182 | } 183 | 184 | public void Tick(float delta) => _scheduler.Run(); 185 | 186 | public unsafe void AddSystem(delegate* method, int poolId) 187 | where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent { 188 | var sysDelegate = Sys; 189 | _scheduler.AddSystem(sysDelegate); 190 | 191 | void Sys(Query> query) { 192 | foreach (var (_, c) in query) 193 | method(ref c.Ref); 194 | } 195 | } 196 | 197 | public unsafe void AddSystem(delegate* method, int poolId) 198 | where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 199 | where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 200 | { 201 | var sysDelegate = Sys; 202 | _scheduler.AddSystem(sysDelegate); 203 | 204 | void Sys(Query> query) { 205 | foreach (var (c1, c2) in query) 206 | method(ref c1.Ref, ref c2.Ref); 207 | } 208 | } 209 | 210 | public unsafe void AddSystem(delegate* method, int poolId) 211 | where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 212 | where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 213 | where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 214 | { 215 | var sysDelegate = Sys; 216 | _scheduler.AddSystem(sysDelegate); 217 | 218 | void Sys(Query> query) { 219 | foreach (var (c1, c2, c3) in query) 220 | method(ref c1.Ref, ref c2.Ref, ref c3.Ref); 221 | } 222 | } 223 | 224 | public unsafe void AddSystem(delegate* method, int poolId) 225 | where T1 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 226 | where T2 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 227 | where T3 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 228 | where T4 : struct, IComponent, IEcsComponent, Xeno.IComponent, Friflo.Engine.ECS.IComponent, FFS.Libraries.StaticEcs.IComponent 229 | { 230 | var sysDelegate = Sys; 231 | _scheduler.AddSystem(sysDelegate); 232 | 233 | void Sys(Query> query) { 234 | foreach (var (c1, c2, c3, c4) in query) 235 | method(ref c1.Ref, ref c2.Ref, ref c3.Ref, ref c4.Ref); 236 | } 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /Benchmark.Xeno/Benchmark.Xeno.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Benchmark._Context/ArrayExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Benchmark; 4 | 5 | public static class ArrayExtensions 6 | { 7 | public static readonly Random Rnd = new(2052513957); 8 | 9 | public static void Shuffle(this T[] array) 10 | { 11 | var n = array.Length; 12 | while (n > 1) 13 | { 14 | var k = Rnd.Next(n--); 15 | (array[n], array[k]) = (array[k], array[n]); 16 | } 17 | } 18 | 19 | public static void Shuffle(this Array array) 20 | { 21 | var n = array.Length; 22 | while (n > 1) 23 | { 24 | var k = Rnd.Next(n--); 25 | var tmp = array.GetValue(n); 26 | array.SetValue(array.GetValue(k), n); 27 | array.SetValue(tmp, k); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Benchmark._Context/Benchmark._Context.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | true 10 | Benchmark.Context 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Benchmark._Context/Context.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Benchmark.Context; 4 | 5 | public static class BenchmarkContext 6 | { 7 | public static T Create(in int entityCount) 8 | { 9 | throw new NotImplementedException(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Benchmark._Context/Ignore.cs: -------------------------------------------------------------------------------- 1 | namespace Benchmark.Context; 2 | 3 | public class IgnoreAttribute : System.Attribute; 4 | -------------------------------------------------------------------------------- /Benchmark._Generator/Benchmark._Generator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1 5 | 12 6 | disable 7 | disable 8 | true 9 | Benchmark.Generator 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Benchmark._Generator/MethodInliner.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | public static class MethodInliner 8 | { 9 | public static MethodDeclarationSyntax InlineMethodCall(this MethodDeclarationSyntax targetMethod, INamedTypeSymbol contextType) 10 | { 11 | var statements = targetMethod.Body?.Statements ?? Enumerable.Empty(); 12 | var newStatements = new List(); 13 | 14 | foreach (var statement in statements) 15 | { 16 | ProcessStatement(statement); 17 | } 18 | 19 | return targetMethod.WithBody(SyntaxFactory.Block(newStatements)); 20 | 21 | void ProcessStatement(StatementSyntax statement) 22 | { 23 | switch (statement) 24 | { 25 | case ExpressionStatementSyntax expressionStatement: 26 | HandleExpression(expressionStatement.Expression); 27 | break; 28 | 29 | case LocalDeclarationStatementSyntax localDeclarationStatement: 30 | HandleVariable(localDeclarationStatement); 31 | break; 32 | 33 | default: 34 | // Recurse for nested blocks (e.g., loops or conditionals) 35 | newStatements.Add(statement); 36 | foreach (var child in statement.ChildNodes().OfType()) 37 | { 38 | ProcessStatement(child); 39 | } 40 | break; 41 | } 42 | } 43 | 44 | void HandleVariable(LocalDeclarationStatementSyntax declaration) 45 | { 46 | var variable = declaration.Declaration.Variables.First(); 47 | var initializer = variable.Initializer?.Value; 48 | 49 | if (initializer is InvocationExpressionSyntax invocation) 50 | { 51 | InlineInvocation(variable.Identifier.ToString(), invocation); 52 | } 53 | else 54 | { 55 | newStatements.Add(declaration); 56 | } 57 | } 58 | 59 | void HandleExpression(ExpressionSyntax expression) 60 | { 61 | if (expression is InvocationExpressionSyntax invocation) 62 | { 63 | InlineInvocation(null, invocation); 64 | } 65 | else 66 | { 67 | newStatements.Add(SyntaxFactory.ExpressionStatement(expression)); 68 | } 69 | } 70 | 71 | void InlineInvocation(string variableName, InvocationExpressionSyntax invocation) 72 | { 73 | var methodName = GetMethodName(invocation, out var genericParameters); 74 | var invocationArguments = invocation.ArgumentList.Arguments.ToArray(); 75 | var (methodSymbol, methodSyntax) = GetMethodDeclaration(methodName, genericParameters, invocationArguments, contextType); 76 | 77 | if (methodSymbol == null || methodSyntax == null) 78 | { 79 | // If method not found, add the original invocation 80 | newStatements.Add(SyntaxFactory.ExpressionStatement(invocation)); 81 | return; 82 | } 83 | 84 | // Recursively inline the method body 85 | var inlinedBody = InlineMethodCall(methodSyntax, contextType).Body ?? SyntaxFactory.Block(); 86 | var body = SyntaxFactory.Block(inlinedBody.Statements); 87 | 88 | // Replace parameters with actual arguments 89 | body = ReplaceArguments(body, methodSymbol, invocationArguments); 90 | 91 | // Replace return statement with assignment if applicable 92 | if (!string.IsNullOrEmpty(variableName)) 93 | { 94 | var returnStatement = body.Statements.LastOrDefault(s => s is ReturnStatementSyntax); 95 | if (returnStatement != null) 96 | { 97 | body = body.ReplaceNode(returnStatement, 98 | SyntaxFactory.ParseStatement($"var {variableName} = {returnStatement.ToFullString().Replace("return", "").Trim()};")); 99 | } 100 | } 101 | 102 | // Add the expanded method body 103 | newStatements.AddRange(body.Statements); 104 | } 105 | } 106 | 107 | private static string GetMethodName(InvocationExpressionSyntax invocation, out TypeSyntax[] genericParameters) 108 | { 109 | if (invocation.Expression is MemberAccessExpressionSyntax memberAccess) 110 | { 111 | genericParameters = memberAccess.Name is GenericNameSyntax genericName 112 | ? genericName.TypeArgumentList.Arguments.ToArray() 113 | : System.Array.Empty(); 114 | 115 | return memberAccess.Name.Identifier.Text; 116 | } 117 | 118 | genericParameters = System.Array.Empty(); 119 | return string.Empty; 120 | } 121 | 122 | private static (IMethodSymbol methodSymbol, MethodDeclarationSyntax methodSyntax) GetMethodDeclaration( 123 | string methodName, 124 | TypeSyntax[] genericParameters, 125 | ArgumentSyntax[] invocationArguments, 126 | INamedTypeSymbol contextType) 127 | { 128 | var method = contextType.GetMembers() 129 | .OfType() 130 | .FirstOrDefault(m => m.Name == methodName 131 | && IsMatchGeneric(m, genericParameters) 132 | && IsMatchArguments(m, invocationArguments)); 133 | 134 | if (method == null) 135 | return (null, null); 136 | 137 | var syntaxRef = method.DeclaringSyntaxReferences.FirstOrDefault(); 138 | var syntax = syntaxRef?.GetSyntax() as MethodDeclarationSyntax; 139 | return (method, syntax); 140 | 141 | static bool IsMatchGeneric(IMethodSymbol methodSymbol, TypeSyntax[] genericParameters) 142 | => methodSymbol.TypeParameters.Length >= genericParameters.Length; 143 | 144 | static bool IsMatchArguments(IMethodSymbol methodSymbol, ArgumentSyntax[] argumentSyntaxes) 145 | => methodSymbol.Parameters.Length == argumentSyntaxes.Length; 146 | } 147 | 148 | private static BlockSyntax ReplaceArguments(BlockSyntax body, IMethodSymbol methodSymbol, ArgumentSyntax[] invocationArguments) 149 | { 150 | var updatedStatements = body.Statements.ToList(); 151 | 152 | for (var i = 0; i < invocationArguments.Length; i++) 153 | { 154 | var argument = invocationArguments[i].ToFullString(); 155 | var parameter = methodSymbol.Parameters[i].Name; 156 | 157 | // Prepend parameter assignment to the method body 158 | updatedStatements.Insert(i, SyntaxFactory.ParseStatement($"var {parameter} = {argument};")); 159 | } 160 | 161 | return SyntaxFactory.Block(updatedStatements); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Benchmark._Generator/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "DebugRoslynSourceGenerator": { 5 | "commandName": "DebugRoslynComponent", 6 | "targetProject": "../Benchmark/Benchmark.csproj" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /Benchmark._Generator/SymbolExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.CodeAnalysis; 5 | using Microsoft.CodeAnalysis.CSharp; 6 | using Microsoft.CodeAnalysis.CSharp.Syntax; 7 | 8 | public static class SymbolExtensions 9 | { 10 | public static List CollectImplementations(this Compilation compilation, INamedTypeSymbol interfaceType, 11 | Func filter = null) 12 | { 13 | var implementations = new List(); 14 | 15 | // Check the current compilation 16 | CollectImplementationsInternal(compilation.Assembly); 17 | 18 | // Check referenced assemblies 19 | foreach (var referencedAssembly in compilation.ReferencedAssemblyNames) 20 | { 21 | var referencedCompilation = compilation.References 22 | .Select(compilation.GetAssemblyOrModuleSymbol) 23 | .OfType() 24 | .FirstOrDefault(assembly => assembly.Identity.Equals(referencedAssembly)); 25 | 26 | if (referencedCompilation != null) CollectImplementationsInternal(referencedCompilation); 27 | } 28 | 29 | return implementations; 30 | 31 | void CollectImplementationsInternal(IAssemblySymbol assembly) 32 | { 33 | var values = assembly.GlobalNamespace.GetNamespaceTypes() 34 | .Where(type => type.AllInterfaces.Contains(interfaceType)); 35 | if (filter != null) values = values.Where(filter); 36 | implementations.AddRange(values); 37 | } 38 | } 39 | 40 | public static TypeDeclarationSyntax GetTypeDeclarationSyntax(this INamedTypeSymbol typeSymbol) { 41 | var syntaxReference = typeSymbol.DeclaringSyntaxReferences.FirstOrDefault(); 42 | if (syntaxReference == null) return null; 43 | 44 | var syntaxNode = syntaxReference.GetSyntax(); 45 | return syntaxNode as TypeDeclarationSyntax; 46 | } 47 | 48 | public static IEnumerable GetNamespaceTypes(this INamespaceSymbol namespaceSymbol) 49 | { 50 | foreach (var member in namespaceSymbol.GetMembers()) 51 | if (member is INamespaceSymbol nestedNamespace) 52 | { 53 | foreach (var nestedType in nestedNamespace.GetNamespaceTypes()) 54 | yield return nestedType; 55 | } 56 | else if (member is INamedTypeSymbol namedType) 57 | yield return namedType; 58 | } 59 | 60 | public static BlockSyntax AsBlock(this StatementSyntax statement) 61 | { 62 | return statement as BlockSyntax ?? SyntaxFactory.Block(statement); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Benchmark._Tests/Benchmark._Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | disable 6 | disable 7 | false 8 | true 9 | true 10 | true 11 | Bentchmark.Tests 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Benchmark._Tests/Benchmark._Tests.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | No 3 | Pessimistic -------------------------------------------------------------------------------- /Benchmark._Tests/Helper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Benchmark; 6 | using BenchmarkDotNet.Attributes; 7 | 8 | namespace Bentchmark.Tests; 9 | 10 | public static class Helper { 11 | public static IEnumerable> GetInjections(Type benchmarkType) { 12 | var paramProps = benchmarkType 13 | .GetProperties(BindingFlags.Instance | BindingFlags.Public) 14 | .Where(p => p.Name != nameof(IBenchmark.EntityCount)) 15 | .Select(p => (p, attr: p.GetCustomAttribute())) 16 | .Where(t => t.attr != null) 17 | .ToArray(); 18 | 19 | var allValues = paramProps 20 | .Select(t => t.attr.Values) 21 | .ToArray(); 22 | 23 | foreach (var combination in CartesianProduct(allValues)) { 24 | yield return benchmark => { 25 | benchmark.EntityCount = Constants.SmallEntityCount; 26 | for (int i = 0; i < paramProps.Length; i++) { 27 | paramProps[i].p.SetValue(benchmark, combination[i]); 28 | } 29 | }; 30 | } 31 | } 32 | 33 | private static IEnumerable CartesianProduct(object[][] sequences) { 34 | int[] indices = new int[sequences.Length]; 35 | while (true) { 36 | var result = new object[sequences.Length]; 37 | for (int i = 0; i < sequences.Length; i++) { 38 | result[i] = sequences[i][indices[i]]; 39 | } 40 | yield return result; 41 | 42 | int k = sequences.Length - 1; 43 | while (k >= 0 && ++indices[k] >= sequences[k].Length) { 44 | indices[k] = 0; 45 | k--; 46 | } 47 | if (k < 0) yield break; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Benchmark._Tests/TestBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Helper = Bentchmark.Tests.Helper; 5 | 6 | namespace Benchmark.Tests; 7 | 8 | public class TestBenchmarks { 9 | [Test] 10 | [TestCaseSource(nameof(GetBenchmarks))] 11 | public void _(T benchmark) where T : IBenchmark, new() { 12 | Assert.NotNull(benchmark); 13 | 14 | benchmark.GlobalSetup(); 15 | 16 | // because of repetative logic we need to check bench will clear and reuse correctly 17 | var i = 10; 18 | while (i-- > 0) { 19 | benchmark.IterationSetup(); 20 | benchmark.Run(); 21 | benchmark.IterationCleanup(); 22 | } 23 | 24 | benchmark.GlobalCleanup(); 25 | } 26 | 27 | private static IEnumerable GetBenchmarks() { 28 | foreach (var benchmarkType in BenchMap.Runs.Values.SelectMany(v => v)) { 29 | if (!benchmarkType.IsAssignableTo(typeof(IBenchmark))) { 30 | continue; 31 | } 32 | 33 | foreach (var injection in Helper.GetInjections(benchmarkType)) { 34 | var benchmark = (IBenchmark)Activator.CreateInstance(benchmarkType); 35 | injection(benchmark); 36 | yield return benchmark; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Benchmark._Tests/TestOverhead.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Helper = Bentchmark.Tests.Helper; 5 | 6 | namespace Benchmark.Tests; 7 | 8 | public class TestOverhead { 9 | [Test] 10 | [TestCaseSource(nameof(GetBenchmarks))] 11 | public void _(T benchmark) where T : IBenchmark, new() { 12 | Assert.NotNull(benchmark); 13 | 14 | benchmark.GlobalSetup(); 15 | 16 | // because of repetative logic we need to check bench will clear and reuse correctly 17 | var i = 3; 18 | while (i-- > 0) { 19 | benchmark.IterationSetup(); 20 | benchmark.IterationCleanup(); 21 | } 22 | 23 | benchmark.GlobalCleanup(); 24 | } 25 | 26 | public static IEnumerable GetBenchmarks() { 27 | foreach (var benchmarkType in BenchMap.Runs.Values.SelectMany(v => v)) { 28 | if (!benchmarkType.IsAssignableTo(typeof(IBenchmark))) { 29 | continue; 30 | } 31 | 32 | foreach (var injection in Helper.GetInjections(benchmarkType)) { 33 | var benchmark = (IBenchmark)Activator.CreateInstance(benchmarkType); 34 | injection(benchmark); 35 | yield return benchmark; 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Benchmark.sh: -------------------------------------------------------------------------------- 1 | # pre-clean 2 | rm -rf ./.benchmark_results 3 | dotnet clean 4 | 5 | # restore and build 6 | dotnet restore -c Release 7 | dotnet build -c Release /p:CheckCacheMisses=false /p:ShortRun=true 8 | if (($? > 0)) 9 | then 10 | exit $?; 11 | fi 12 | 13 | dotnet test -c Release --no-build 14 | if (($? > 0)) 15 | then 16 | exit $?; 17 | fi 18 | 19 | dotnet run --project Benchmark/Benchmark.csproj -c Release --no-build /p:CheckCacheMisses=false /p:ShortRun=true 20 | 21 | rm report.md 22 | 23 | # Prepare the report file 24 | echo "# LOCAL RUN BENCHMARKS:\n---" >> report.md 25 | echo "HW Info:\n" >> report.md 26 | cat .benchmark_results/hwinfo >> report.md 27 | echo "\n" >> report.md 28 | 29 | # Find and sort the markdown files by their first line 30 | find .benchmark_results -name '*.md' -print0 | while IFS= read -r -d '' file; do 31 | first_line=$(head -n 1 "$file") 32 | echo "$first_line|$file" 33 | done | sort | while IFS='|' read -r first_line file; do 34 | cat "$file" >> report.md 35 | echo -e "\n" >> report.md 36 | done 37 | 38 | # post-clean 39 | rm -rf ./.benchmark_results 40 | dotnet clean -c Release -------------------------------------------------------------------------------- /Benchmark.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | False -------------------------------------------------------------------------------- /Benchmark/Benchmark.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | disable 7 | disable 8 | CHECK_CACHE_MISSES 9 | SHORT_RUN 10 | true 11 | pdbonly 12 | true 13 | true 14 | 15 | 16 | 17 | TRACE 18 | 19 | 20 | 21 | TRACE; 22 | 23 | 24 | 25 | false 26 | false 27 | 28 | 29 | 30 | 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 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | Sources\%(RecursiveDir)%(FileName)%(Extension) 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add1Component.cs: -------------------------------------------------------------------------------- 1 | using Benchmark.Context; 2 | using BenchmarkDotNet.Attributes; 3 | 4 | namespace Benchmark.Benchmarks.Entities.AddComponent; 5 | 6 | [ArtifactsPath(".benchmark_results/" + nameof(Add1Component))] 7 | [MemoryDiagnoser] 8 | 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class Add1Component : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.Warmup(0); 26 | Context.FinishSetup(); 27 | } 28 | 29 | [IterationSetup] 30 | public void IterationSetup() 31 | { 32 | Context.CreateEntities(_entitySet); 33 | } 34 | 35 | [Benchmark] 36 | public void Run() 37 | { 38 | Context.AddComponent(_entitySet, 0, default(Component1)); 39 | } 40 | 41 | [IterationCleanup] 42 | public void IterationCleanup() 43 | { 44 | Context.DeleteEntities(_entitySet); 45 | } 46 | 47 | [GlobalCleanup] 48 | public void GlobalCleanup() 49 | { 50 | Context.Cleanup(); 51 | Context.Dispose(); 52 | Context = default; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add1ComponentRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.AddComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Add1ComponentRandomOrder))] 9 | [MemoryDiagnoser] 10 | 11 | #if CHECK_CACHE_MISSES 12 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 13 | #endif 14 | public abstract class Add1ComponentRandomOrder : IBenchmark where T : IBenchmarkContext 15 | { 16 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 17 | 18 | public T Context { get; set; } 19 | private TE[] _entitySet; 20 | 21 | [GlobalSetup] 22 | public void GlobalSetup() 23 | { 24 | Context = BenchmarkContext.Create(EntityCount); 25 | Context.Setup(); 26 | _entitySet = Context.PrepareSet(EntityCount); 27 | Context.Warmup(0); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet); 35 | _entitySet.Shuffle(); 36 | } 37 | 38 | [Benchmark] 39 | public void Run() 40 | { 41 | Context.AddComponent(_entitySet, 0, default(Component1)); 42 | } 43 | 44 | [IterationCleanup] 45 | public void IterationCleanup() 46 | { 47 | Context.DeleteEntities(_entitySet); 48 | } 49 | 50 | [GlobalCleanup] 51 | public void GlobalCleanup() 52 | { 53 | Context.Cleanup(); 54 | Context.Dispose(); 55 | Context = default; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add1RandomComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.AddComponent; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(Add1RandomComponent))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class Add1RandomComponent : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | private TE[] _tmp; 19 | 20 | 21 | [GlobalSetup] 22 | public void GlobalSetup() 23 | { 24 | Context = BenchmarkContext.Create(EntityCount); 25 | Context.Setup(); 26 | _entitySet = Context.PrepareSet(EntityCount); 27 | _tmp = Context.PrepareSet(1); 28 | Context.Warmup(0); 29 | Context.Warmup(1); 30 | Context.Warmup(2); 31 | Context.Warmup(3); 32 | Context.FinishSetup(); 33 | } 34 | 35 | [IterationSetup] 36 | public void IterationSetup() 37 | { 38 | Context.CreateEntities(_entitySet); 39 | } 40 | 41 | [Benchmark] 42 | public void Run() 43 | { 44 | for (var _i = 0; _i < EntityCount; _i++) { 45 | _tmp[0] = _entitySet[_i]; 46 | switch (ArrayExtensions.Rnd.Next() % 4) 47 | { 48 | case 0: 49 | Context.AddComponent(_tmp, 0, default(Component1)); 50 | break; 51 | case 1: 52 | Context.AddComponent(_tmp, 1, default(Component2)); 53 | break; 54 | case 2: 55 | Context.AddComponent(_tmp, 2, default(Component3)); 56 | break; 57 | case 3: 58 | Context.AddComponent(_tmp, 3, default(Component4)); 59 | break; 60 | } 61 | } 62 | } 63 | 64 | [IterationCleanup] 65 | public void IterationCleanup() 66 | { 67 | Context.DeleteEntities(_entitySet); 68 | } 69 | 70 | [GlobalCleanup] 71 | public void GlobalCleanup() 72 | { 73 | Context.Cleanup(); 74 | Context.Dispose(); 75 | Context = default; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add1RandomComponentRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.AddComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Add1RandomComponentRandomOrder))] 9 | [MemoryDiagnoser] 10 | 11 | #if CHECK_CACHE_MISSES 12 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 13 | #endif 14 | public abstract class Add1RandomComponentRandomOrder : IBenchmark where T : IBenchmarkContext 15 | { 16 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | private TE[] _tmp; 20 | 21 | [GlobalSetup] 22 | public void GlobalSetup() 23 | { 24 | Context = BenchmarkContext.Create(EntityCount); 25 | Context.Setup(); 26 | _entitySet = Context.PrepareSet(EntityCount); 27 | _tmp = Context.PrepareSet(1); 28 | 29 | Context.Warmup(0); 30 | Context.Warmup(1); 31 | Context.Warmup(2); 32 | Context.Warmup(3); 33 | Context.FinishSetup(); 34 | } 35 | 36 | 37 | [IterationSetup] 38 | public void IterationSetup() 39 | { 40 | Context.CreateEntities(_entitySet); 41 | _entitySet.Shuffle(); 42 | } 43 | 44 | [Benchmark] 45 | public void Run() 46 | { 47 | for (var _i = 0; _i < EntityCount; _i++) { 48 | _tmp[0] = _entitySet[_i]; 49 | switch (ArrayExtensions.Rnd.Next() % 4) 50 | { 51 | case 0: 52 | Context.AddComponent(_tmp, 0, default(Component1)); 53 | break; 54 | case 1: 55 | Context.AddComponent(_tmp, 1, default(Component2)); 56 | break; 57 | case 2: 58 | Context.AddComponent(_tmp, 2, default(Component3)); 59 | break; 60 | case 3: 61 | Context.AddComponent(_tmp, 3, default(Component4)); 62 | break; 63 | } 64 | } 65 | } 66 | 67 | [IterationCleanup] 68 | public void IterationCleanup() 69 | { 70 | Context.DeleteEntities(_entitySet); 71 | } 72 | 73 | [GlobalCleanup] 74 | public void GlobalCleanup() 75 | { 76 | Context.Cleanup(); 77 | Context.Dispose(); 78 | Context = default; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add2Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.AddComponent; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(Add2Components))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class Add2Components : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | Context.Warmup(0); 27 | Context.FinishSetup(); 28 | } 29 | 30 | [IterationSetup] 31 | public void IterationSetup() 32 | { 33 | Context.CreateEntities(_entitySet); 34 | } 35 | 36 | [Benchmark] 37 | public void Run() 38 | { 39 | Context.AddComponent(_entitySet, 0, default(Component1), default(Component2)); 40 | } 41 | 42 | [IterationCleanup] 43 | public void IterationCleanup() 44 | { 45 | Context.DeleteEntities(_entitySet); 46 | } 47 | 48 | [GlobalCleanup] 49 | public void GlobalCleanup() 50 | { 51 | Context.Cleanup(); 52 | Context.Dispose(); 53 | Context = default; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add2ComponentsRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.AddComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Add2ComponentsRandomOrder))] 9 | [MemoryDiagnoser] 10 | 11 | #if CHECK_CACHE_MISSES 12 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 13 | #endif 14 | public abstract class Add2ComponentsRandomOrder : IBenchmark where T : IBenchmarkContext 15 | { 16 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 17 | 18 | public T Context { get; set; } 19 | private TE[] _entitySet; 20 | 21 | 22 | [GlobalSetup] 23 | public void GlobalSetup() 24 | { 25 | Context = BenchmarkContext.Create(EntityCount); 26 | Context.Setup(); 27 | _entitySet = Context.PrepareSet(EntityCount); 28 | Context.Warmup(0); 29 | Context.FinishSetup(); 30 | } 31 | 32 | [IterationSetup] 33 | public void IterationSetup() 34 | { 35 | Context.CreateEntities(_entitySet); 36 | _entitySet.Shuffle(); 37 | } 38 | 39 | [Benchmark] 40 | public void Run() 41 | { 42 | Context.AddComponent(_entitySet, 0, default(Component1), default(Component2)); 43 | } 44 | 45 | [IterationCleanup] 46 | public void IterationCleanup() 47 | { 48 | Context.DeleteEntities(_entitySet); 49 | } 50 | 51 | [GlobalCleanup] 52 | public void GlobalCleanup() 53 | { 54 | Context.Cleanup(); 55 | Context.Dispose(); 56 | Context = default; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add2RandomComponents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.AddComponent; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(Add2RandomComponents))] 8 | [MemoryDiagnoser] 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class Add2RandomComponents : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | public T Context { get; set; } 16 | private TE[] _entitySet; 17 | private TE[] _tmp; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | _tmp = Context.PrepareSet(1); 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.Warmup(2); 29 | Context.Warmup(3); 30 | Context.FinishSetup(); 31 | } 32 | 33 | [IterationSetup] 34 | public void IterationSetup() 35 | { 36 | Context.CreateEntities(_entitySet); 37 | } 38 | 39 | [Benchmark] 40 | public void Run() 41 | { 42 | for (var _i = 0; _i < EntityCount; _i++) { 43 | _tmp[0] = _entitySet[_i]; 44 | switch (ArrayExtensions.Rnd.Next() % 4) 45 | { 46 | case 0: 47 | Context.AddComponent(_tmp, 0, default(Component1), default(Component2)); 48 | break; 49 | case 1: 50 | Context.AddComponent(_tmp, 1, default(Component2), default(Component3)); 51 | break; 52 | case 2: 53 | Context.AddComponent(_tmp, 2, default(Component3), default(Component4)); 54 | break; 55 | case 3: 56 | Context.AddComponent(_tmp, 3, default(Component4), default(Component1)); 57 | break; 58 | } 59 | } 60 | } 61 | 62 | [IterationCleanup] 63 | public void IterationCleanup() 64 | { 65 | Context.DeleteEntities(_entitySet); 66 | } 67 | 68 | [GlobalCleanup] 69 | public void GlobalCleanup() 70 | { 71 | Context.Cleanup(); 72 | Context.Dispose(); 73 | Context = default; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add2RandomComponentsRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.AddComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Add2RandomComponentsRandomOrder))] 9 | [MemoryDiagnoser] 10 | 11 | #if CHECK_CACHE_MISSES 12 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 13 | #endif 14 | public abstract class Add2RandomComponentsRandomOrder : IBenchmark where T : IBenchmarkContext 15 | { 16 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | private TE[] _tmp; 20 | 21 | [GlobalSetup] 22 | public void GlobalSetup() 23 | { 24 | Context = BenchmarkContext.Create(EntityCount); 25 | Context.Setup(); 26 | _entitySet = Context.PrepareSet(EntityCount); 27 | _tmp = Context.PrepareSet(1); 28 | Context.Warmup(0); 29 | Context.Warmup(1); 30 | Context.Warmup(2); 31 | Context.Warmup(3); 32 | Context.FinishSetup(); 33 | } 34 | 35 | [IterationSetup] 36 | public void IterationSetup() 37 | { 38 | Context.CreateEntities(_entitySet); 39 | _entitySet.Shuffle(); 40 | } 41 | 42 | [Benchmark] 43 | public void Run() 44 | { 45 | for (var _i = 0; _i < EntityCount; _i++) { 46 | _tmp[0] = _entitySet[_i]; 47 | switch (ArrayExtensions.Rnd.Next() % 4) 48 | { 49 | case 0: 50 | Context.AddComponent(_tmp, 0, default(Component1), default(Component2)); 51 | break; 52 | case 1: 53 | Context.AddComponent(_tmp, 1, default(Component2), default(Component3)); 54 | break; 55 | case 2: 56 | Context.AddComponent(_tmp, 2, default(Component3), default(Component4)); 57 | break; 58 | case 3: 59 | Context.AddComponent(_tmp, 3, default(Component4), default(Component1)); 60 | break; 61 | } 62 | } 63 | } 64 | 65 | [IterationCleanup] 66 | public void IterationCleanup() 67 | { 68 | Context.DeleteEntities(_entitySet); 69 | } 70 | 71 | [GlobalCleanup] 72 | public void GlobalCleanup() 73 | { 74 | Context.Cleanup(); 75 | Context.Dispose(); 76 | Context = default; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add3Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.AddComponent; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(Add3Components))] 8 | [MemoryDiagnoser] 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class Add3Components : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.Warmup(0); 26 | Context.FinishSetup(); 27 | } 28 | 29 | [IterationSetup] 30 | public void IterationSetup() 31 | { 32 | Context.CreateEntities(_entitySet); 33 | } 34 | 35 | [Benchmark] 36 | public void Run() 37 | { 38 | Context.AddComponent(_entitySet, 0, default(Component1), default(Component2), default(Component3)); 39 | } 40 | 41 | [IterationCleanup] 42 | public void IterationCleanup() 43 | { 44 | Context.DeleteEntities(_entitySet); 45 | } 46 | 47 | [GlobalCleanup] 48 | public void GlobalCleanup() 49 | { 50 | Context.Cleanup(); 51 | Context.Dispose(); 52 | Context = default; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add3ComponentsRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.AddComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Add3ComponentsRandomOrder))] 9 | [MemoryDiagnoser] 10 | 11 | #if CHECK_CACHE_MISSES 12 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 13 | #endif 14 | public abstract class Add3ComponentsRandomOrder : IBenchmark where T : IBenchmarkContext 15 | { 16 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 17 | 18 | public T Context { get; set; } 19 | private TE[] _entitySet; 20 | 21 | 22 | [GlobalSetup] 23 | public void GlobalSetup() 24 | { 25 | Context = BenchmarkContext.Create(EntityCount); 26 | Context.Setup(); 27 | _entitySet = Context.PrepareSet(EntityCount); 28 | Context.Warmup(0); 29 | Context.FinishSetup(); 30 | } 31 | 32 | [IterationSetup] 33 | public void IterationSetup() 34 | { 35 | Context.CreateEntities(_entitySet); 36 | _entitySet.Shuffle(); 37 | } 38 | 39 | [Benchmark] 40 | public void Run() 41 | { 42 | Context.AddComponent(_entitySet, 0, default(Component1), default(Component2), default(Component3)); 43 | } 44 | 45 | [IterationCleanup] 46 | public void IterationCleanup() 47 | { 48 | Context.DeleteEntities(_entitySet); 49 | } 50 | 51 | [GlobalCleanup] 52 | public void GlobalCleanup() 53 | { 54 | Context.Cleanup(); 55 | Context.Dispose(); 56 | Context = default; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add3RandomComponents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.AddComponent; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(Add3RandomComponents))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class Add3RandomComponents : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | private TE[] _tmp; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | _tmp = Context.PrepareSet(1); 27 | Context.Warmup(0); 28 | Context.Warmup(1); 29 | Context.Warmup(2); 30 | Context.Warmup(3); 31 | Context.FinishSetup(); 32 | } 33 | 34 | [IterationSetup] 35 | public void IterationSetup() 36 | { 37 | Context.CreateEntities(_entitySet); 38 | } 39 | 40 | [Benchmark] 41 | public void Run() 42 | { 43 | for (var _i = 0; _i < EntityCount; _i++) { 44 | _tmp[0] = _entitySet[_i]; 45 | switch (ArrayExtensions.Rnd.Next() % 4) { 46 | case 0: 47 | Context.AddComponent(_tmp, 0, default(Component1), default(Component2), default(Component3)); 48 | break; 49 | case 1: 50 | Context.AddComponent(_tmp, 1, default(Component2), default(Component3), default(Component4)); 51 | break; 52 | case 2: 53 | Context.AddComponent(_tmp, 2, default(Component3), default(Component4), default(Component1)); 54 | break; 55 | case 3: 56 | Context.AddComponent(_tmp, 3, default(Component4), default(Component1), default(Component2)); 57 | break; 58 | } 59 | } 60 | } 61 | 62 | [IterationCleanup] 63 | public void IterationCleanup() 64 | { 65 | Context.DeleteEntities(_entitySet); 66 | } 67 | 68 | [GlobalCleanup] 69 | public void GlobalCleanup() 70 | { 71 | Context.Cleanup(); 72 | Context.Dispose(); 73 | Context = default; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add3RandomComponentsRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.AddComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Add3RandomComponentsRandomOrder))] 9 | [MemoryDiagnoser] 10 | 11 | #if CHECK_CACHE_MISSES 12 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 13 | #endif 14 | public abstract class Add3RandomComponentsRandomOrder : IBenchmark where T : IBenchmarkContext 15 | { 16 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | private TE[] _tmp; 20 | 21 | [GlobalSetup] 22 | public void GlobalSetup() 23 | { 24 | Context = BenchmarkContext.Create(EntityCount); 25 | Context.Setup(); 26 | _entitySet = Context.PrepareSet(EntityCount); 27 | _tmp = Context.PrepareSet(1); 28 | Context.Warmup(0); 29 | Context.Warmup(1); 30 | Context.Warmup(2); 31 | Context.Warmup(3); 32 | Context.FinishSetup(); 33 | } 34 | 35 | [IterationSetup] 36 | public void IterationSetup() 37 | { 38 | Context.CreateEntities(_entitySet); 39 | _entitySet.Shuffle(); 40 | } 41 | 42 | [Benchmark] 43 | public void Run() 44 | { 45 | for (var _i = 0; _i < EntityCount; _i++) { 46 | _tmp[0] = _entitySet[_i]; 47 | switch (ArrayExtensions.Rnd.Next() % 4) { 48 | case 0: 49 | Context.AddComponent(_tmp, 0, default(Component1), default(Component2), default(Component3)); 50 | break; 51 | case 1: 52 | Context.AddComponent(_tmp, 1, default(Component2), default(Component3), default(Component4)); 53 | break; 54 | case 2: 55 | Context.AddComponent(_tmp, 2, default(Component3), default(Component4), default(Component1)); 56 | break; 57 | case 3: 58 | Context.AddComponent(_tmp, 3, default(Component4), default(Component1), default(Component2)); 59 | break; 60 | } 61 | } 62 | } 63 | 64 | [IterationCleanup] 65 | public void IterationCleanup() 66 | { 67 | Context.DeleteEntities(_entitySet); 68 | } 69 | 70 | [GlobalCleanup] 71 | public void GlobalCleanup() 72 | { 73 | Context.Cleanup(); 74 | Context.Dispose(); 75 | Context = default; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add4Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.AddComponent; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(Add4Components))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class Add4Components : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | Context.Warmup(0); 27 | Context.FinishSetup(); 28 | } 29 | 30 | [IterationSetup] 31 | public void IterationSetup() 32 | { 33 | Context.CreateEntities(_entitySet); 34 | } 35 | 36 | [Benchmark] 37 | public void Run() 38 | { 39 | Context.AddComponent(_entitySet, 0, default(Component1), default(Component2), default(Component3), default(Component4)); 40 | } 41 | 42 | [IterationCleanup] 43 | public void IterationCleanup() 44 | { 45 | Context.DeleteEntities(_entitySet); 46 | } 47 | 48 | [GlobalCleanup] 49 | public void GlobalCleanup() 50 | { 51 | Context.Cleanup(); 52 | Context.Dispose(); 53 | Context = default; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/AddComponent/Add4ComponentsRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.AddComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Add4ComponentsRandomOrder))] 9 | [MemoryDiagnoser] 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class Add4ComponentsRandomOrder : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | 21 | [GlobalSetup] 22 | public void GlobalSetup() 23 | { 24 | Context = BenchmarkContext.Create(EntityCount); 25 | Context.Setup(); 26 | _entitySet = Context.PrepareSet(EntityCount); 27 | Context.Warmup(0); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet); 35 | _entitySet.Shuffle(); 36 | } 37 | 38 | [Benchmark] 39 | public void Run() 40 | { 41 | Context.AddComponent(_entitySet, 0, default(Component1), default(Component2), default(Component3), default(Component4)); 42 | } 43 | 44 | [IterationCleanup] 45 | public void IterationCleanup() 46 | { 47 | Context.DeleteEntities(_entitySet); 48 | } 49 | 50 | [GlobalCleanup] 51 | public void GlobalCleanup() 52 | { 53 | Context.Cleanup(); 54 | Context.Dispose(); 55 | Context = default; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/CreateEntity/CreateEmptyEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.CreateEntity; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(CreateEmptyEntity))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class CreateEmptyEntity : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | Context.FinishSetup(); 25 | } 26 | 27 | [IterationSetup] 28 | public void IterationSetup() 29 | { 30 | _entitySet = Context.PrepareSet(EntityCount); 31 | } 32 | 33 | [Benchmark] 34 | public void Run() 35 | { 36 | Context.CreateEntities(_entitySet); 37 | } 38 | 39 | [IterationCleanup] 40 | public void IterationCleanup() 41 | { 42 | Context.DeleteEntities(_entitySet); 43 | } 44 | 45 | [GlobalCleanup] 46 | public void GlobalCleanup() 47 | { 48 | Context.Cleanup(); 49 | Context.Dispose(); 50 | Context = default; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/CreateEntity/CreateEntityWith1Component.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.CreateEntity; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(CreateEntityWith1Component))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class CreateEntityWith1Component : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | Context.Warmup(0); 25 | Context.FinishSetup(); 26 | 27 | _entitySet = Context.PrepareSet(EntityCount); 28 | } 29 | 30 | [Benchmark] 31 | public void Run() 32 | { 33 | Context.CreateEntities(_entitySet, 0, default(Component1)); 34 | } 35 | 36 | [IterationCleanup] 37 | public void IterationCleanup() 38 | { 39 | Context.DeleteEntities(_entitySet); 40 | } 41 | 42 | [GlobalCleanup] 43 | public void GlobalCleanup() 44 | { 45 | Context.Cleanup(); 46 | Context.Dispose(); 47 | Context = default; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/CreateEntity/CreateEntityWith1RandomComponent.cs: -------------------------------------------------------------------------------- 1 | using Benchmark.Context; 2 | using BenchmarkDotNet.Attributes; 3 | 4 | namespace Benchmark.Benchmarks.Entities.CreateEntity; 5 | 6 | [ArtifactsPath(".benchmark_results/" + nameof(CreateEntityWith1RandomComponent))] 7 | [MemoryDiagnoser] 8 | 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class CreateEntityWith1RandomComponent : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | public T Context { get; set; } 16 | private TE[] _entitySet; 17 | private TE[] _tmp; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | _tmp = Context.PrepareSet(1); 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.Warmup(2); 29 | Context.Warmup(3); 30 | Context.FinishSetup(); 31 | } 32 | 33 | [Benchmark] 34 | public void Run() 35 | { 36 | for (int _i = 0; _i < _entitySet.Length; _i++) { 37 | _tmp[0] = _entitySet[_i]; 38 | switch (ArrayExtensions.Rnd.Next() % 4) 39 | { 40 | case 0: 41 | Context.CreateEntities(_tmp, 0, default(Component1)); 42 | break; 43 | case 1: 44 | Context.CreateEntities(_tmp, 1, default(Component2)); 45 | break; 46 | case 2: 47 | Context.CreateEntities(_tmp, 2, default(Component3)); 48 | break; 49 | case 3: 50 | Context.CreateEntities(_tmp, 3, default(Component4)); 51 | break; 52 | } 53 | _entitySet[_i] = _tmp[0]; 54 | } 55 | } 56 | 57 | [IterationCleanup] 58 | public void IterationCleanup() 59 | { 60 | Context.DeleteEntities(_entitySet); 61 | } 62 | 63 | [GlobalCleanup] 64 | public void GlobalCleanup() 65 | { 66 | Context.Cleanup(); 67 | Context.Dispose(); 68 | Context = default; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/CreateEntity/CreateEntityWith2Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.CreateEntity; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(CreateEntityWith2Components))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class CreateEntityWith2Components : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.Warmup(0); 26 | Context.FinishSetup(); 27 | } 28 | 29 | [Benchmark] 30 | public void Run() 31 | { 32 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2)); 33 | } 34 | 35 | [IterationCleanup] 36 | public void IterationCleanup() 37 | { 38 | Context.DeleteEntities(_entitySet); 39 | } 40 | 41 | [GlobalCleanup] 42 | public void GlobalCleanup() 43 | { 44 | Context.Cleanup(); 45 | Context.Dispose(); 46 | Context = default; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/CreateEntity/CreateEntityWith2RandomComponents.cs: -------------------------------------------------------------------------------- 1 | using Benchmark.Context; 2 | using BenchmarkDotNet.Attributes; 3 | 4 | namespace Benchmark.Benchmarks.Entities.CreateEntity; 5 | 6 | [ArtifactsPath(".benchmark_results/" + nameof(CreateEntityWith2RandomComponents))] 7 | [MemoryDiagnoser] 8 | 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class CreateEntityWith2RandomComponents : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | public T Context { get; set; } 16 | private TE[] _entitySet; 17 | private TE[] _tmp; 18 | 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | _tmp = Context.PrepareSet(1); 27 | Context.Warmup(0); 28 | Context.Warmup(1); 29 | Context.Warmup(2); 30 | Context.Warmup(3); 31 | Context.FinishSetup(); 32 | } 33 | 34 | [Benchmark] 35 | public void Run() 36 | { 37 | for (int _i = 0; _i < _entitySet.Length; _i++) { 38 | _tmp[0] = _entitySet[_i]; 39 | switch (ArrayExtensions.Rnd.Next() % 4) { 40 | case 0: 41 | Context.CreateEntities(_tmp, 0, default(Component1), default(Component2)); 42 | break; 43 | case 1: 44 | Context.CreateEntities(_tmp, 1, default(Component2), default(Component3)); 45 | break; 46 | case 2: 47 | Context.CreateEntities(_tmp, 2, default(Component3), default(Component4)); 48 | break; 49 | case 3: 50 | Context.CreateEntities(_tmp, 3, default(Component4), default(Component1)); 51 | break; 52 | } 53 | _entitySet[_i] = _tmp[0]; 54 | } 55 | } 56 | 57 | [IterationCleanup] 58 | public void IterationCleanup() 59 | { 60 | Context.DeleteEntities(_entitySet); 61 | } 62 | 63 | [GlobalCleanup] 64 | public void GlobalCleanup() 65 | { 66 | Context.Cleanup(); 67 | Context.Dispose(); 68 | Context = default; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/CreateEntity/CreateEntityWith3Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.CreateEntity; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(CreateEntityWith3Components))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class CreateEntityWith3Components : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.Warmup(0); 26 | Context.FinishSetup(); 27 | } 28 | 29 | [Benchmark] 30 | public void Run() 31 | { 32 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3)); 33 | } 34 | 35 | [IterationCleanup] 36 | public void IterationCleanup() 37 | { 38 | Context.DeleteEntities(_entitySet); 39 | } 40 | 41 | [GlobalCleanup] 42 | public void GlobalCleanup() 43 | { 44 | Context.Cleanup(); 45 | Context.Dispose(); 46 | Context = default; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/CreateEntity/CreateEntityWith3RandomComponents.cs: -------------------------------------------------------------------------------- 1 | using Benchmark.Context; 2 | using BenchmarkDotNet.Attributes; 3 | 4 | namespace Benchmark.Benchmarks.Entities.CreateEntity; 5 | 6 | [ArtifactsPath(".benchmark_results/" + nameof(CreateEntityWith3RandomComponents))] 7 | [MemoryDiagnoser] 8 | 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class CreateEntityWith3RandomComponents : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | public T Context { get; set; } 16 | private TE[] _entitySet; 17 | private TE[] _tmp; 18 | 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | _tmp = Context.PrepareSet(1); 27 | Context.Warmup(0); 28 | Context.Warmup(1); 29 | Context.Warmup(2); 30 | Context.Warmup(3); 31 | Context.FinishSetup(); 32 | } 33 | 34 | [Benchmark] 35 | public void Run() 36 | { 37 | for (int _i = 0; _i < _entitySet.Length; _i++) { 38 | _tmp[0] = _entitySet[_i]; 39 | switch (ArrayExtensions.Rnd.Next() % 4) { 40 | case 0: 41 | Context.CreateEntities(_tmp, 0, default(Component1), default(Component2), default(Component3)); 42 | break; 43 | case 1: 44 | Context.CreateEntities(_tmp, 1, default(Component2), default(Component3), default(Component4)); 45 | break; 46 | case 2: 47 | Context.CreateEntities(_tmp, 2, default(Component3), default(Component4), default(Component1)); 48 | break; 49 | case 3: 50 | Context.CreateEntities(_tmp, 3, default(Component4), default(Component1), default(Component2)); 51 | break; 52 | } 53 | _entitySet[_i] = _tmp[0]; 54 | } 55 | } 56 | 57 | [IterationCleanup] 58 | public void IterationCleanup() 59 | { 60 | Context.DeleteEntities(_entitySet); 61 | } 62 | 63 | [GlobalCleanup] 64 | public void GlobalCleanup() 65 | { 66 | Context.Cleanup(); 67 | Context.Dispose(); 68 | Context = default; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/CreateEntity/CreateEntityWith4Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.CreateEntity; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(CreateEntityWith4Components))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class CreateEntityWith4Components : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.Warmup(0); 26 | Context.FinishSetup(); 27 | } 28 | 29 | [Benchmark] 30 | public void Run() 31 | { 32 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3), default(Component4)); 33 | } 34 | 35 | [IterationCleanup] 36 | public void IterationCleanup() 37 | { 38 | Context.DeleteEntities(_entitySet); 39 | } 40 | 41 | [GlobalCleanup] 42 | public void GlobalCleanup() 43 | { 44 | Context.Cleanup(); 45 | Context.Dispose(); 46 | Context = default; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/DeleteEntity/DeleteEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.DeleteEntity; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(DeleteEntity))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class DeleteEntity : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.FinishSetup(); 26 | } 27 | 28 | [IterationSetup] 29 | public void IterationSetup() 30 | { 31 | Context.CreateEntities(_entitySet); 32 | } 33 | 34 | [Benchmark] 35 | public void Run() 36 | { 37 | Context.DeleteEntities(_entitySet); 38 | 39 | _entitySet = Context.PrepareSet(0); 40 | } 41 | 42 | [IterationCleanup] 43 | public void IterationCleanup() 44 | { 45 | Context.DeleteEntities(_entitySet); 46 | } 47 | 48 | [GlobalCleanup] 49 | public void GlobalCleanup() 50 | { 51 | Context.Cleanup(); 52 | Context.Dispose(); 53 | Context = default; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/RemoveComponent/Remove1Component.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.RemoveComponent; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(Remove1Component))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class Remove1Component : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | 18 | private TE[] _entitySet; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | 26 | Context.Warmup(0); 27 | _entitySet = Context.PrepareSet(EntityCount); 28 | Context.FinishSetup(); 29 | 30 | } 31 | 32 | [IterationSetup] 33 | public void IterationSetup() 34 | { 35 | Context.CreateEntities(_entitySet, 0, default(Component1)); 36 | } 37 | 38 | [Benchmark] 39 | public void Run() 40 | { 41 | Context.RemoveComponent(_entitySet, 0); 42 | } 43 | 44 | [IterationCleanup] 45 | public void IterationCleanup() 46 | { 47 | if (!Context.DeletesEntityOnLastComponentDeletion) 48 | Context.DeleteEntities(_entitySet); 49 | } 50 | 51 | [GlobalCleanup] 52 | public void GlobalCleanup() 53 | { 54 | Context.Cleanup(); 55 | Context.Dispose(); 56 | Context = default; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/RemoveComponent/Remove1ComponentRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.RemoveComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Remove1ComponentRandomOrder))] 9 | [MemoryDiagnoser] 10 | 11 | #if CHECK_CACHE_MISSES 12 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 13 | #endif 14 | public abstract class Remove1ComponentRandomOrder : IBenchmark where T : IBenchmarkContext 15 | { 16 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 17 | public T Context { get; set; } 18 | 19 | private TE[] _entitySet; 20 | 21 | 22 | [GlobalSetup] 23 | public void GlobalSetup() 24 | { 25 | Context = BenchmarkContext.Create(EntityCount); 26 | Context.Setup(); 27 | Context.Warmup(0); 28 | _entitySet = Context.PrepareSet(EntityCount); 29 | Context.FinishSetup(); 30 | } 31 | 32 | [IterationSetup] 33 | public void IterationSetup() 34 | { 35 | Context.CreateEntities(_entitySet, 0, default(Component1)); 36 | _entitySet.Shuffle(); 37 | } 38 | 39 | [Benchmark] 40 | public void Run() 41 | { 42 | Context.RemoveComponent(_entitySet, 0); 43 | } 44 | 45 | [IterationCleanup] 46 | public void IterationCleanup() 47 | { 48 | if (!Context.DeletesEntityOnLastComponentDeletion) 49 | Context.DeleteEntities(_entitySet); 50 | } 51 | 52 | [GlobalCleanup] 53 | public void GlobalCleanup() 54 | { 55 | Context.Cleanup(); 56 | Context.Dispose(); 57 | Context = default; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/RemoveComponent/Remove2Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.RemoveComponent; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(Remove2Components))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class Remove2Components : IBenchmark where T : class, IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | 25 | Context.Warmup(0); 26 | _entitySet = Context.PrepareSet(EntityCount); 27 | Context.FinishSetup(); 28 | 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.RemoveComponent(_entitySet, 0); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | if (!Context.DeletesEntityOnLastComponentDeletion) 47 | Context.DeleteEntities(_entitySet); 48 | } 49 | 50 | [GlobalCleanup] 51 | public void GlobalCleanup() 52 | { 53 | Context.Cleanup(); 54 | Context.Dispose(); 55 | Context = default; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/RemoveComponent/Remove2ComponentsRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.RemoveComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Remove2ComponentsRandomOrder))] 9 | [MemoryDiagnoser] 10 | 11 | #if CHECK_CACHE_MISSES 12 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 13 | #endif 14 | public abstract class Remove2ComponentsRandomOrder : IBenchmark where T : class, IBenchmarkContext 15 | { 16 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | 21 | [GlobalSetup] 22 | public void GlobalSetup() 23 | { 24 | Context = BenchmarkContext.Create(EntityCount); 25 | Context.Setup(); 26 | Context.Warmup(0); 27 | _entitySet = Context.PrepareSet(EntityCount); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2)); 35 | _entitySet.Shuffle(); 36 | } 37 | 38 | [Benchmark] 39 | public void Run() 40 | { 41 | Context.RemoveComponent(_entitySet, 0); 42 | } 43 | 44 | [IterationCleanup] 45 | public void IterationCleanup() 46 | { 47 | if (!Context.DeletesEntityOnLastComponentDeletion) 48 | Context.DeleteEntities(_entitySet); 49 | } 50 | 51 | [GlobalCleanup] 52 | public void GlobalCleanup() 53 | { 54 | Context.Cleanup(); 55 | Context.Dispose(); 56 | Context = default; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/RemoveComponent/Remove3Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.RemoveComponent; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(Remove3Components))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class Remove3Components : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | 25 | Context.Warmup(0); 26 | _entitySet = Context.PrepareSet(EntityCount); 27 | Context.FinishSetup(); 28 | 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.RemoveComponent(_entitySet, 0); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | if (!Context.DeletesEntityOnLastComponentDeletion) 47 | Context.DeleteEntities(_entitySet); 48 | } 49 | 50 | [GlobalCleanup] 51 | public void GlobalCleanup() 52 | { 53 | Context.Cleanup(); 54 | Context.Dispose(); 55 | Context = default; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/RemoveComponent/Remove3ComponentsRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.RemoveComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Remove3ComponentsRandomOrder))] 9 | [MemoryDiagnoser] 10 | 11 | #if CHECK_CACHE_MISSES 12 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 13 | #endif 14 | public abstract class Remove3ComponentsRandomOrder : IBenchmark where T : IBenchmarkContext 15 | { 16 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | 21 | [GlobalSetup] 22 | public void GlobalSetup() 23 | { 24 | Context = BenchmarkContext.Create(EntityCount); 25 | Context.Setup(); 26 | Context.Warmup(0); 27 | _entitySet = Context.PrepareSet(EntityCount); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3)); 35 | _entitySet.Shuffle(); 36 | } 37 | 38 | [Benchmark] 39 | public void Run() 40 | { 41 | Context.RemoveComponent(_entitySet, 0); 42 | } 43 | 44 | [IterationCleanup] 45 | public void IterationCleanup() 46 | { 47 | if (!Context.DeletesEntityOnLastComponentDeletion) 48 | Context.DeleteEntities(_entitySet); 49 | } 50 | 51 | [GlobalCleanup] 52 | public void GlobalCleanup() 53 | { 54 | Context.Cleanup(); 55 | Context.Dispose(); 56 | Context = default; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/RemoveComponent/Remove4Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.RemoveComponent; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(Remove4Components))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class Remove4Components : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | 25 | Context.Warmup(0); 26 | _entitySet = Context.PrepareSet(EntityCount); 27 | Context.FinishSetup(); 28 | 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3), default(Component4)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.RemoveComponent(_entitySet, 0); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | if (!Context.DeletesEntityOnLastComponentDeletion) 47 | Context.DeleteEntities(_entitySet); 48 | } 49 | 50 | [GlobalCleanup] 51 | public void GlobalCleanup() 52 | { 53 | Context.Cleanup(); 54 | Context.Dispose(); 55 | Context = default; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/RemoveComponent/Remove4ComponentsRandomOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using Benchmark.Utils; 4 | using BenchmarkDotNet.Attributes; 5 | 6 | namespace Benchmark.Benchmarks.Entities.RemoveComponent; 7 | 8 | [ArtifactsPath(".benchmark_results/" + nameof(Remove4ComponentsRandomOrder))] 9 | [MemoryDiagnoser] 10 | 11 | #if CHECK_CACHE_MISSES 12 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 13 | #endif 14 | public abstract class Remove4ComponentsRandomOrder : IBenchmark where T : IBenchmarkContext 15 | { 16 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | 21 | [GlobalSetup] 22 | public void GlobalSetup() 23 | { 24 | Context = BenchmarkContext.Create(EntityCount); 25 | Context.Setup(); 26 | Context.Warmup(0); 27 | _entitySet = Context.PrepareSet(EntityCount); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3), default(Component4)); 35 | _entitySet.Shuffle(); 36 | } 37 | 38 | [Benchmark] 39 | public void Run() 40 | { 41 | Context.RemoveComponent(_entitySet, 0); 42 | } 43 | 44 | [IterationCleanup] 45 | public void IterationCleanup() 46 | { 47 | if (!Context.DeletesEntityOnLastComponentDeletion) 48 | Context.DeleteEntities(_entitySet); 49 | } 50 | 51 | [GlobalCleanup] 52 | public void GlobalCleanup() 53 | { 54 | Context.Cleanup(); 55 | Context.Dispose(); 56 | Context = default; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/FourRemoveOneComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(FourRemoveOneComponent))] 8 | [MemoryDiagnoser] 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class FourRemoveOneComponent : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.Warmup(0); 26 | Context.Warmup(1); 27 | Context.FinishSetup(); 28 | } 29 | 30 | [IterationSetup] 31 | public void IterationSetup() 32 | { 33 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3), default(Component4)); 34 | } 35 | 36 | [Benchmark] 37 | public void Run() 38 | { 39 | Context.RemoveComponent(_entitySet, 1); 40 | } 41 | 42 | [IterationCleanup] 43 | public void IterationCleanup() 44 | { 45 | Context.DeleteEntities(_entitySet); 46 | } 47 | 48 | [GlobalCleanup] 49 | public void GlobalCleanup() 50 | { 51 | Context.Cleanup(); 52 | Context.Dispose(); 53 | Context = default; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/FourRemoveThreeComponents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(FourRemoveThreeComponents))] 8 | [MemoryDiagnoser] 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class FourRemoveThreeComponents : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.Warmup(0); 26 | Context.Warmup(1); 27 | Context.FinishSetup(); 28 | } 29 | 30 | [IterationSetup] 31 | public void IterationSetup() 32 | { 33 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3), 34 | default(Component4)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.RemoveComponent(_entitySet, 1); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | Context.DeleteEntities(_entitySet); 47 | } 48 | 49 | [GlobalCleanup] 50 | public void GlobalCleanup() 51 | { 52 | Context.Cleanup(); 53 | Context.Dispose(); 54 | Context = default; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/FourRemoveTwoComponents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(FourRemoveTwoComponents))] 8 | [MemoryDiagnoser] 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class FourRemoveTwoComponents : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.Warmup(0); 26 | Context.Warmup(1); 27 | Context.FinishSetup(); 28 | } 29 | 30 | [IterationSetup] 31 | public void IterationSetup() 32 | { 33 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3), 34 | default(Component4)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.RemoveComponent(_entitySet, 1); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | Context.DeleteEntities(_entitySet); 47 | } 48 | 49 | [GlobalCleanup] 50 | public void GlobalCleanup() 51 | { 52 | Context.Cleanup(); 53 | Context.Dispose(); 54 | Context = default; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/OneAddOneComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(OneAddOneComponent))] 8 | [MemoryDiagnoser] 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class OneAddOneComponent : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.Warmup(0); 26 | Context.Warmup(1); 27 | Context.FinishSetup(); 28 | } 29 | 30 | [IterationSetup] 31 | public void IterationSetup() 32 | { 33 | Context.CreateEntities(_entitySet, 0, default(Component1)); 34 | } 35 | 36 | [Benchmark] 37 | public void Run() 38 | { 39 | Context.AddComponent(_entitySet, 1, default(Component2)); 40 | } 41 | 42 | [IterationCleanup] 43 | public void IterationCleanup() 44 | { 45 | Context.DeleteEntities(_entitySet); 46 | } 47 | 48 | [GlobalCleanup] 49 | public void GlobalCleanup() 50 | { 51 | Context.Cleanup(); 52 | Context.Dispose(); 53 | Context = default; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/OneAddThreeComponents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(OneAddThreeComponents))] 8 | [MemoryDiagnoser] 9 | #if CHECK_CACHE_MISSES 10 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 11 | #endif 12 | public abstract class OneAddThreeComponents : IBenchmark where T : IBenchmarkContext 13 | { 14 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 15 | 16 | public T Context { get; set; } 17 | private TE[] _entitySet; 18 | 19 | [GlobalSetup] 20 | public void GlobalSetup() 21 | { 22 | Context = BenchmarkContext.Create(EntityCount); 23 | Context.Setup(); 24 | _entitySet = Context.PrepareSet(EntityCount); 25 | Context.Warmup(0); 26 | Context.Warmup(1); 27 | Context.FinishSetup(); 28 | } 29 | 30 | [IterationSetup] 31 | public void IterationSetup() 32 | { 33 | Context.CreateEntities(_entitySet, 0, default(Component1)); 34 | } 35 | 36 | [Benchmark] 37 | public void Run() 38 | { 39 | Context.AddComponent(_entitySet, 1, default(Component2), default(Component3), default(Component4)); 40 | } 41 | 42 | [IterationCleanup] 43 | public void IterationCleanup() 44 | { 45 | Context.DeleteEntities(_entitySet); 46 | } 47 | 48 | [GlobalCleanup] 49 | public void GlobalCleanup() 50 | { 51 | Context.Cleanup(); 52 | Context.Dispose(); 53 | Context = default; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/OneAddTwoComponents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(OneAddTwoComponents))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class OneAddTwoComponents : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.AddComponent(_entitySet, 1, default(Component2), default(Component3)); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | Context.DeleteEntities(_entitySet); 47 | } 48 | 49 | [GlobalCleanup] 50 | public void GlobalCleanup() 51 | { 52 | Context.Cleanup(); 53 | Context.Dispose(); 54 | Context = default; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/ThreeAddOneComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(ThreeAddOneComponent))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class ThreeAddOneComponent : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.AddComponent(_entitySet, 1, default(Component4)); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | Context.DeleteEntities(_entitySet); 47 | } 48 | 49 | [GlobalCleanup] 50 | public void GlobalCleanup() 51 | { 52 | Context.Cleanup(); 53 | Context.Dispose(); 54 | Context = default; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/ThreeRemoveOneComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(ThreeRemoveOneComponent))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class ThreeRemoveOneComponent : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.RemoveComponent(_entitySet, 1); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | Context.DeleteEntities(_entitySet); 47 | } 48 | 49 | [GlobalCleanup] 50 | public void GlobalCleanup() 51 | { 52 | Context.Cleanup(); 53 | Context.Dispose(); 54 | Context = default; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/ThreeRemoveTwoComponents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(ThreeRemoveTwoComponents))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class ThreeRemoveTwoComponents : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2), default(Component3)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.RemoveComponent(_entitySet, 1); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | Context.DeleteEntities(_entitySet); 47 | } 48 | 49 | [GlobalCleanup] 50 | public void GlobalCleanup() 51 | { 52 | Context.Cleanup(); 53 | Context.Dispose(); 54 | Context = default; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/TwoAddOneComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(TwoAddOneComponent))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class TwoAddOneComponent : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.AddComponent(_entitySet, 1, default(Component3)); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | Context.DeleteEntities(_entitySet); 47 | } 48 | 49 | [GlobalCleanup] 50 | public void GlobalCleanup() 51 | { 52 | Context.Cleanup(); 53 | Context.Dispose(); 54 | Context = default; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/TwoAddTwoComponents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(TwoAddTwoComponents))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class TwoAddTwoComponents : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.AddComponent(_entitySet, 1, default(Component3), default(Component4)); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | Context.DeleteEntities(_entitySet); 47 | } 48 | 49 | [GlobalCleanup] 50 | public void GlobalCleanup() 51 | { 52 | Context.Cleanup(); 53 | Context.Dispose(); 54 | Context = default; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Entities/StructuralChanges/TwoRemoveOneComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Benchmark.Context; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Benchmark.Benchmarks.Entities.StructuralChanges; 6 | 7 | [ArtifactsPath(".benchmark_results/" + nameof(TwoRemoveOneComponent))] 8 | [MemoryDiagnoser] 9 | 10 | #if CHECK_CACHE_MISSES 11 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 12 | #endif 13 | public abstract class TwoRemoveOneComponent : IBenchmark where T : IBenchmarkContext 14 | { 15 | [Params(Constants.EntityCount)] public int EntityCount { get; set; } 16 | 17 | public T Context { get; set; } 18 | private TE[] _entitySet; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | _entitySet = Context.PrepareSet(EntityCount); 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.FinishSetup(); 29 | } 30 | 31 | [IterationSetup] 32 | public void IterationSetup() 33 | { 34 | Context.CreateEntities(_entitySet, 0, default(Component1), default(Component2)); 35 | } 36 | 37 | [Benchmark] 38 | public void Run() 39 | { 40 | Context.RemoveComponent(_entitySet, 1); 41 | } 42 | 43 | [IterationCleanup] 44 | public void IterationCleanup() 45 | { 46 | Context.DeleteEntities(_entitySet); 47 | } 48 | 49 | [GlobalCleanup] 50 | public void GlobalCleanup() 51 | { 52 | Context.Cleanup(); 53 | Context.Dispose(); 54 | Context = default; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/IBenchmark.cs: -------------------------------------------------------------------------------- 1 | using Benchmark.Context; 2 | 3 | namespace Benchmark; 4 | 5 | public interface IBenchmark 6 | { 7 | public int EntityCount { get; set; } 8 | 9 | public void GlobalSetup() 10 | { 11 | } 12 | 13 | public void IterationSetup() 14 | { 15 | } 16 | 17 | public void Run(); 18 | 19 | public void IterationCleanup() 20 | { 21 | } 22 | 23 | public void GlobalCleanup() 24 | { 25 | } 26 | } 27 | 28 | public interface IBenchmark : IBenchmark where T : IBenchmarkContext; 29 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Systems/SystemWith1Component.cs: -------------------------------------------------------------------------------- 1 | using Benchmark.Context; 2 | using BenchmarkDotNet.Attributes; 3 | 4 | namespace Benchmark.Benchmarks.Systems; 5 | 6 | [ArtifactsPath(".benchmark_results/" + nameof(SystemWith1Component))] 7 | [MemoryDiagnoser] 8 | #if CHECK_CACHE_MISSES 9 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 10 | #endif 11 | public abstract class SystemWith1Component : IBenchmark where T : IBenchmarkContext 12 | { 13 | [Params(Constants.SystemEntityCount)] public int EntityCount { get; set; } 14 | [Params(0, 10)] public int Padding { get; set; } 15 | 16 | public T Context { get; set; } 17 | 18 | private TE[] set; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | Context.Warmup(0); 26 | Context.Warmup(1); 27 | 28 | unsafe 29 | { 30 | // set up systems 31 | Context.AddSystem(&Update, 0); 32 | } 33 | 34 | Context.FinishSetup(); 35 | 36 | set = Context.PrepareSet(1); 37 | var _i = 0; 38 | while (_i < EntityCount) { 39 | { 40 | Context.CreateEntities(set, 0, new Component1 { Value = 0 }); 41 | _i++; 42 | } 43 | 44 | for (var j = 0; j < Padding; ++j) { 45 | Context.CreateEntities(set, 1, default(Padding1)); 46 | ++_i; 47 | 48 | if (_i >= EntityCount) return; 49 | } 50 | } 51 | } 52 | 53 | [GlobalCleanup] 54 | public void GlobalCleanup() 55 | { 56 | Context.Cleanup(); 57 | Context.Dispose(); 58 | Context = default; 59 | } 60 | 61 | [Benchmark] 62 | public void Run() 63 | { 64 | Context.Tick(0.1f); 65 | } 66 | 67 | private static void Update(ref Component1 c1) 68 | { 69 | c1.Value++; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Systems/SystemWith2Components.cs: -------------------------------------------------------------------------------- 1 | using Benchmark.Context; 2 | using BenchmarkDotNet.Attributes; 3 | 4 | namespace Benchmark.Benchmarks.Systems; 5 | 6 | [ArtifactsPath(".benchmark_results/" + nameof(SystemWith2Components))] 7 | [MemoryDiagnoser] 8 | #if CHECK_CACHE_MISSES 9 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 10 | #endif 11 | public abstract class SystemWith2Components : IBenchmark where T : IBenchmarkContext 12 | { 13 | [Params(Constants.SystemEntityCount)] public int EntityCount { get; set; } 14 | [Params(0, 10)] public int Padding { get; set; } 15 | 16 | public T Context { get; set; } 17 | 18 | private TE[] set; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.Warmup(2); 29 | 30 | unsafe 31 | { 32 | // set up systems 33 | Context.AddSystem(&Update, 0); 34 | } 35 | 36 | Context.FinishSetup(); 37 | 38 | set = Context.PrepareSet(1); 39 | var _i = 0; 40 | while (_i < EntityCount) { 41 | { 42 | Context.CreateEntities(set, 0, default(Component1), new Component2 { Value = 1 }); 43 | _i++; 44 | } 45 | 46 | for (var j = 0; j < Padding; ++j) { 47 | switch (j % 2) { 48 | case 0: Context.CreateEntities(set, 1, default(Component1)); break; 49 | case 1: Context.CreateEntities(set, 2, default(Component2)); break; 50 | } 51 | ++_i; 52 | 53 | if (_i >= EntityCount) return; 54 | } 55 | } 56 | } 57 | 58 | [GlobalCleanup] 59 | public void GlobalCleanup() 60 | { 61 | Context.Cleanup(); 62 | Context.Dispose(); 63 | Context = default; 64 | } 65 | 66 | [Benchmark] 67 | public void Run() 68 | { 69 | Context.Tick(0.1f); 70 | } 71 | 72 | private static void Update(ref Component1 c1, ref Component2 c2) 73 | { 74 | c1.Value += c2.Value; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Benchmark/Benchmarks/Systems/SystemWith3Components.cs: -------------------------------------------------------------------------------- 1 | using Benchmark.Context; 2 | using BenchmarkDotNet.Attributes; 3 | 4 | namespace Benchmark.Benchmarks.Systems; 5 | 6 | [ArtifactsPath(".benchmark_results/" + nameof(SystemWith3Components))] 7 | [MemoryDiagnoser] 8 | #if CHECK_CACHE_MISSES 9 | [HardwareCounters(BenchmarkDotNet.Diagnosers.HardwareCounter.CacheMisses)] 10 | #endif 11 | public abstract class SystemWith3Components : IBenchmark where T : IBenchmarkContext 12 | { 13 | [Params(Constants.SystemEntityCount)] public int EntityCount { get; set; } 14 | [Params(0, 10)] public int Padding { get; set; } 15 | 16 | public T Context { get; set; } 17 | 18 | private TE[] set; 19 | 20 | [GlobalSetup] 21 | public void GlobalSetup() 22 | { 23 | Context = BenchmarkContext.Create(EntityCount); 24 | Context.Setup(); 25 | 26 | Context.Warmup(0); 27 | Context.Warmup(1); 28 | Context.Warmup(2); 29 | Context.Warmup(3); 30 | 31 | unsafe 32 | { 33 | // set up systems 34 | Context.AddSystem(&Update, 0); 35 | } 36 | 37 | Context.FinishSetup(); 38 | 39 | set = Context.PrepareSet(1); 40 | var _i = 0; 41 | while (_i < EntityCount) { 42 | { 43 | Context.CreateEntities(set, 0, default(Component1), new Component2 { Value = 1 }, new Component3 { Value = 1 }); 44 | _i++; 45 | } 46 | 47 | for (var j = 0; j < Padding; ++j) { 48 | switch (j % 3) { 49 | case 0: Context.CreateEntities(set, 1, default(Component1)); break; 50 | case 1: Context.CreateEntities(set, 2, default(Component2)); break; 51 | case 2: Context.CreateEntities(set, 3, default(Component3)); break; 52 | } 53 | ++_i; 54 | 55 | if (_i >= EntityCount) return; 56 | } 57 | } 58 | } 59 | 60 | [GlobalCleanup] 61 | public void GlobalCleanup() 62 | { 63 | Context.Cleanup(); 64 | Context.Dispose(); 65 | Context = default; 66 | } 67 | 68 | [Benchmark] 69 | public void Run() 70 | { 71 | Context.Tick(0.1f); 72 | } 73 | 74 | private static void Update(ref Component1 c1, ref Component2 c2, ref Component3 c3) 75 | { 76 | c1.Value += c2.Value + c3.Value; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Benchmark/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace Benchmark; 2 | 3 | public static class Constants 4 | { 5 | public const int Seed = 0x7ADE7455; 6 | public const int SmallEntityCount = 1_000; 7 | public const int MidEntityCount = 100_000; 8 | public const int LargeEntityCount = 500_000; 9 | 10 | #if SHORT_RUN 11 | public const int EntityCount = SmallEntityCount; 12 | public const int SystemEntityCount = SmallEntityCount; 13 | #else 14 | public const int EntityCount = MidEntityCount; 15 | public const int SystemEntityCount = MidEntityCount; 16 | #endif 17 | } -------------------------------------------------------------------------------- /Benchmark/Options.cs: -------------------------------------------------------------------------------- 1 | namespace Benchmark; 2 | 3 | public class Options 4 | { 5 | public bool PrintList { get; private set; } 6 | public string[] Contexts { get; private set; } 7 | public string Benchmark { get; private set; } 8 | public string[] Benchmarks { get; private set; } 9 | public bool ShortRun { get; private set; } 10 | 11 | public static Options Parse(in string[] args) 12 | { 13 | var result = new Options(); 14 | 15 | var _i = 0; 16 | while (_i < args.Length) 17 | { 18 | if (args[_i] == "--list") 19 | { 20 | result.PrintList = true; 21 | break; 22 | } 23 | 24 | if (args[_i] == "--short") result.ShortRun = true; 25 | if (args[_i].StartsWith("contexts=")) result.Contexts = args[_i].Split("=")[1].Split(","); 26 | if (args[_i].StartsWith("benchmarks=")) result.Benchmarks = args[_i].Split("=")[1].Split(","); 27 | if (args[_i].StartsWith("benchmark=")) result.Benchmark = args[_i].Split("=")[1]; 28 | _i++; 29 | } 30 | 31 | return result; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Benchmark/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text.Json; 8 | using Benchmark; 9 | using Benchmark.Utils; 10 | using BenchmarkDotNet.Columns; 11 | using BenchmarkDotNet.Configs; 12 | using BenchmarkDotNet.Engines; 13 | using BenchmarkDotNet.Jobs; 14 | using BenchmarkDotNet.Reports; 15 | using BenchmarkDotNet.Running; 16 | #if DEBUG 17 | using BenchmarkDotNet.Toolchains.InProcess.Emit; 18 | #endif 19 | 20 | //* 21 | // clear previous results 22 | if (Directory.Exists(".benchmark_results")) 23 | Directory.Delete(".benchmark_results", true); 24 | 25 | // parse cmd args 26 | var options = Options.Parse(args); 27 | Console.WriteLine("Using Options:"); 28 | Console.WriteLine(JsonSerializer.Serialize(options, JsonSerializerOptions.Default)); 29 | 30 | // configure jobs 31 | var shortJob = Job.ShortRun 32 | #if DEBUG 33 | .WithToolchain(InProcessEmitToolchain.Instance) 34 | #endif 35 | .WithStrategy(RunStrategy.Monitoring) 36 | .WithInvocationCount(1) 37 | .WithIterationCount(4) 38 | .WithEvaluateOverhead(false) 39 | .WithWarmupCount(0) 40 | .Apply(); 41 | 42 | var precisionJob = Job.Default 43 | #if DEBUG 44 | .WithToolchain(InProcessEmitToolchain.Instance) 45 | #endif 46 | .WithStrategy(RunStrategy.Throughput) 47 | .WithInvocationCount(1) 48 | .WithUnrollFactor(1) 49 | .Apply(); 50 | 51 | // configure runner 52 | IConfig configuration = DefaultConfig.Instance 53 | .WithOptions(ConfigOptions.DisableOptimizationsValidator) 54 | .WithOption(ConfigOptions.JoinSummary, true) 55 | .AddColumn(new ContextColumn()) 56 | .AddColumn(HashColumn.Default) 57 | .WithSummaryStyle(SummaryStyle.Default.WithRatioStyle(RatioStyle.Trend)) 58 | .HideColumns(Column.Gen0, Column.Gen1, Column.Gen2, Column.Type, Column.Method, Column.Namespace); 59 | 60 | if (options.PrintList) 61 | { 62 | File.WriteAllText("benchmarks.txt", string.Join("\n", BenchMap.Runs.Keys.Select(b => b.Name[..^2]))); 63 | return 0; 64 | } 65 | 66 | var baseBenchmarkTypes = BenchMap.Runs.Keys.ToArray(); 67 | if (!string.IsNullOrEmpty(options.Benchmark)) 68 | baseBenchmarkTypes = [baseBenchmarkTypes.FirstOrDefault(ctx => ctx.Name[..^2] == options.Benchmark)]; 69 | else if (options.Benchmarks is { Length: > 0 }) 70 | baseBenchmarkTypes = baseBenchmarkTypes.Where(ctx => options.Benchmarks.Any(c => ctx.Name.Contains(c))).ToArray(); 71 | 72 | Console.WriteLine("Benchmarks:"); 73 | Console.WriteLine(string.Join("\n", baseBenchmarkTypes.Select(b => $"\t{b.Name}"))); 74 | Console.WriteLine(); 75 | 76 | var contextTypes = BenchMap.Contexts.Keys.ToArray(); 77 | if (options.Contexts is { Length: > 0 }) 78 | contextTypes = contextTypes.Where(ctx => options.Contexts.Any(c => ctx.Name.Contains(c))).ToArray(); 79 | 80 | Console.WriteLine("Contexts:"); 81 | Console.WriteLine(string.Join("\n", contextTypes.Select(b => $"\t{b.Name}"))); 82 | Console.WriteLine(); 83 | 84 | Console.WriteLine($"{baseBenchmarkTypes.Length * contextTypes.Length} total benchmarks."); 85 | 86 | // run benchmarks 87 | foreach (var baseBenchmarkType in baseBenchmarkTypes) 88 | { 89 | // this is all benchmarks 90 | var benchmarkAllTypes = BenchMap.Runs[baseBenchmarkType]; 91 | 92 | // we keep only those which intersects with lists of selected context types 93 | var benchmarkTypes = new List(); 94 | foreach (var contextBenchTypes in contextTypes.Select(t => BenchMap.Contexts[t])) 95 | benchmarkTypes.AddRange(benchmarkAllTypes.Where(t => contextBenchTypes.Contains(t))); 96 | 97 | var benchmarkSwitcher = BenchmarkSwitcher.FromTypes(benchmarkTypes.ToArray()); 98 | 99 | var job = options.ShortRun ? shortJob : precisionJob; 100 | var summaries = benchmarkSwitcher.RunAll(configuration.AddJob(job)).ToArray(); 101 | 102 | // post process benchmark reports 103 | foreach (var summary in summaries) 104 | { 105 | var rootDir = summary.ResultsDirectoryPath; 106 | var rootDirInfo = new DirectoryInfo(rootDir); 107 | var name = rootDirInfo.Parent.Name; 108 | 109 | var reports = Directory.GetFiles(rootDir, "*.md", SearchOption.TopDirectoryOnly); 110 | foreach (var report in reports) 111 | { 112 | var contents = File.ReadAllLines(report).ToList(); 113 | 114 | if (contents[0] == "```") 115 | { 116 | var hwInfo = new List(); 117 | 118 | // remove hw info 119 | hwInfo.Add(contents[0]); 120 | contents.RemoveAt(0); 121 | while (contents[0] != "```") 122 | { 123 | hwInfo.Add(contents[0]); 124 | contents.RemoveAt(0); 125 | } 126 | 127 | hwInfo.Add(contents[0]); 128 | contents.RemoveAt(0); 129 | 130 | File.WriteAllText(".benchmark_results/hwinfo", string.Join("\n", hwInfo)); 131 | } 132 | 133 | File.WriteAllText(report, $"# {name}\n\n{string.Join("\n", contents)}"); 134 | } 135 | } 136 | } 137 | //*/ 138 | 139 | return 0; 140 | -------------------------------------------------------------------------------- /Benchmark/Utils/ContextColumn.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Columns; 2 | using BenchmarkDotNet.Reports; 3 | using BenchmarkDotNet.Running; 4 | 5 | namespace Benchmark.Utils; 6 | 7 | public class ContextColumn : IColumn 8 | { 9 | public string Id => "Context"; 10 | public string ColumnName => "Context"; 11 | public bool AlwaysShow => true; 12 | public ColumnCategory Category => ColumnCategory.Job; 13 | public int PriorityInCategory => -1; 14 | public bool IsNumeric => false; 15 | public UnitType UnitType => UnitType.Dimensionless; 16 | public string Legend => "Ecs context for given benchmark"; 17 | 18 | public string GetValue(Summary summary, BenchmarkCase benchmarkCase) => benchmarkCase.Descriptor.Type.Name.Split('_')[1]; 19 | 20 | public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyle style) => benchmarkCase.Descriptor.Type.Name.Split('_')[1]; 21 | 22 | public bool IsDefault(Summary summary, BenchmarkCase benchmarkCase) => true; 23 | 24 | public bool IsAvailable(Summary summary) => true; 25 | } 26 | -------------------------------------------------------------------------------- /Benchmark/Utils/HashColumn.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using BenchmarkDotNet.Columns; 3 | using BenchmarkDotNet.Reports; 4 | using BenchmarkDotNet.Running; 5 | 6 | namespace Benchmark.Utils; 7 | 8 | public class HashColumn : IColumn 9 | { 10 | public static readonly IColumn Default = new HashColumn(); 11 | private HashColumn() {} 12 | 13 | public string GetValue(Summary summary, BenchmarkCase benchmarkCase) 14 | { 15 | foreach (var report in summary.Reports) 16 | { 17 | if (report.BenchmarkCase != benchmarkCase) 18 | continue; 19 | 20 | var hashes = GetHashesFromOutput(report, "// Hash: "); 21 | if (hashes.Length == 0) 22 | break; 23 | 24 | var first = hashes[0]; 25 | return hashes.Any(h => h != first) ? $"!{first}" : $" {first}"; 26 | } 27 | 28 | return "?"; 29 | } 30 | 31 | private static string[] GetHashesFromOutput(BenchmarkReport report, string prefix) 32 | { 33 | return ( 34 | from executeResults in report.ExecuteResults 35 | from extraOutputLine in executeResults.StandardOutput.Where(line => line.StartsWith(prefix)) 36 | select extraOutputLine[prefix.Length..]).ToArray(); 37 | } 38 | 39 | public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyle style) => GetValue(summary, benchmarkCase); 40 | public bool IsDefault(Summary summary, BenchmarkCase benchmarkCase) => false; 41 | public bool IsAvailable(Summary summary) => true; 42 | public string Id => nameof(HashColumn); 43 | public string ColumnName => "Hash"; 44 | public bool AlwaysShow => true; 45 | public ColumnCategory Category => ColumnCategory.Custom; 46 | public int PriorityInCategory => 0; 47 | public bool IsNumeric => false; 48 | public UnitType UnitType => UnitType.Dimensionless; 49 | public string Legend => "Hash"; 50 | public override string ToString() => ColumnName; 51 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 1. Fork 4 | 2. Implement Context \ Benchmark 5 | 3. Check with tests 6 | 4. Create PR 7 | 8 | Simple as it is. 9 | 10 | ## Notices 11 | 12 | ### Source Generation Awareness 13 | 14 | Benchmarks are source generated. Seriously. 15 | 16 | The idea is to get code from *Context and pass it as code inside *Benchmark so it will be some kind of pseudo hand written bench without mess of abstractions (for runtime). 17 | This limits the usage of some freaking stuff but for now it's working, so use other references and benchmarks as reference. 18 | 19 | Also none of contexts or benchmarks are run directly. They're just a source of source code for generation. 20 | As for now 600+ unique pairs of Benchmark <-> Context generated and each of them are used it runtime. 21 | 22 | You can see the Raw_Runner and use it for testing and profiling each particular pair or subsets of benchmarks using generated BenchMap. 23 | 24 | Have fun at least. 25 | -------------------------------------------------------------------------------- /FFS.StaticEcs.Workaround/FFS.StaticEcs.Workaround.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | disable 6 | disable 7 | true 8 | true 9 | 10 | 11 | 12 | FFS_ECS_DISABLE_TAGS;FFS_ECS_DISABLE_MASKS 13 | 14 | 15 | 16 | FFS_ECS_DISABLE_TAGS;FFS_ECS_DISABLE_MASKS 17 | 18 | 19 | 20 | 21 | Src\%(RecursiveDir)/%(FileName)%(Extension) 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Dmytro 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, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LeoECS/LeoECS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | src\%(RecursiveDir)/%(FileName)%(Extension) 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /LeoECSLite/LeoECSLite.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | disable 8 | true 9 | true 10 | 11 | 12 | 13 | TRACE;LEOECSLITE_NO_SANITIZE_CHECKS 14 | 15 | 16 | 17 | TRACE;LEOECSLITE_NO_SANITIZE_CHECKS 18 | 19 | 20 | 21 | 22 | src\%(RecursiveDir)/%(FileName)%(Extension) 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!WARNING] 2 | > Benchmark is under active development all API, integrations and set of benchmarks is subject to change! 3 | > 4 | 5 | # Latest run 6 | 7 | [![Test](https://github.com/blackbone/other-ecs-benchmarks/actions/workflows/test.yml/badge.svg)](https://github.com/blackbone/other-ecs-benchmarks/actions/workflows/test.yml) 8 | [![Run parallel benchmarks](https://github.com/blackbone/other-ecs-benchmarks/actions/workflows/benchmark.yml/badge.svg)](https://github.com/blackbone/other-ecs-benchmarks/actions/workflows/benchmark.yml) 9 | 10 | updated with actions and can be found [here](https://gist.github.com/blackbone/6d254a684cf580441bf58690ad9485c3) 11 | 12 | # What is all about? 13 | 14 | General idea is to hide implementation of each ECS under context abstraction and work with it from benchmark 15 | implementations. 16 | 17 | Benchmarks design follow 2 rules which I try to balance with: 18 | 19 | * **Strict usage** - to ensure all benchmarks are running with same flow to avoid cheating. 20 | * **Features utilization** - to allow implementations to run in perfomant way. 21 | 22 | General flow of any benchmark execution is divided into 3 steps: 23 | 24 | * Preparation 25 | * Creating world 26 | * Creating initial entities if needed 27 | * Initialize filters and queries or other stuff which used to gain perfomance 28 | * Benchmark call 29 | * Acquiring lock of world 30 | * Run main logic 31 | * Commiting changes 32 | * Cleanup - mostly omitted 33 | 34 | > [!IMPORTANT] 35 | > Don't search truth here. There won't be any. 36 | 37 | # Implemented contexts 38 | 39 | | ECS | Version | Implemented | Verified | Notes | 40 | |---------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------|:-----------:|:--------:|:--------------------------------------:| 41 | | [ArrayECS](https://github.com/blackbone/other-ecs-benchmarks/tree/main/ArrayECS) | [1.0.0](#) | ✅ | ✅ | dumb ecs on arrays | 42 | | [Arch](https://github.com/genaray/Arch) | [2.1.0-beta](https://www.nuget.org/packages/Arch/2.1.0-beta) | ✅ | ❌ | Source Generator 2.1.0 / Systems 1.1.0 | 43 | | [fennecs](https://fennecs.tech/) | [0.5.16-beta](https://www.nuget.org/packages/fennecs/0.5.16-beta) | ✅ | ❌ | N/A | 44 | | [Morpeh](https://github.com/scellecs/morpeh) | [stage-2024.1.1](https://github.com/scellecs/morpeh/releases/tag/2024.1.1) | ✅ | ❌ | N/A | 45 | | [DragonECS](https://github.com/DCFApixels/DragonECS) | [0.9.9](https://github.com/DCFApixels/DragonECS/releases/tag/0.9.9) | ✅ | ❌ | N/A | 46 | | [LeoECS](https://github.com/Leopotam/ecs) | [2023.6.22](https://github.com/Leopotam/ecs/releases/tag/2023.6.22) | ✅ | ❌ | N/A | 47 | | [LeoECSLite](https://github.com/Leopotam/ecslite) | [2024.5.22](https://github.com/Leopotam/ecslite/releases/tag/2024.5.22) | ✅ | ❌ | N/A | 48 | | [DefaultECS](https://github.com/Doraku/DefaultEcs) | [0.18.0-beta01](https://github.com/Doraku/DefaultEcs/releases/tag/0.18.0-beta01) | ✅ | ❌ | Analyzer 0.17.0 | 49 | | [FlecsNET](https://github.com/BeanCheeseBurrito/Flecs.NET) | [4.0.4-build.548](https://www.nuget.org/packages/Flecs.NET.Release/4.0.4-build.548) | ✅ | ❌ | N/A | 50 | | [TinyEcs](https://github.com/andreakarasho/TinyEcs) | [2.0.0](https://www.nuget.org/packages/TinyEcs.Main/2.0.0) | ✅ | ❌ | N/A | 51 | | [Xeno](https://github.com/blackbone/xeno) | [0.1.7](https://github.com/blackbone/xeno/releases/tag/0.1.7) | ✅ | ✅ | N/A | 52 | | [FriFlo](https://github.com/friflo/Friflo.Engine.ECS) | [3.2.3](https://www.nuget.org/packages/Friflo.Engine.ECS/3.2.3) | ✅ | ❌ | N/A | 53 | | [StaticEcs](https://github.com/Felid-Force-Studios/StaticEcs) | [0.9.80](https://github.com/Felid-Force-Studios/StaticEcs/commit/b39e7e5ba0fb37d8836b571f40272d63709389bc) | ✅ | ✅ | N/A | 54 | | [Massive ECS](https://github.com/nilpunch/massive-ecs) | [v19.0.2](https://github.com/nilpunch/massive-ecs/releases/tag/v19.0.2) | ✅ | ✅ | N/A | 55 | 56 | # Implemented benchmarks 57 | 58 | | Benchmark | Description | 59 | |-----------------------------------------------|-------------------------------------------------------------------------| 60 | | Create Empty Entity | Creates [EntityCount] empty entities | 61 | | Create Entity With N Components | Creates [EntityCount] entitites with N components | 62 | | Add N Components | Adds N components to [EntityCount] entities | 63 | | Remove N Components | Adds N components to [EntityCount] entities | 64 | | System with N Components | Performs simple operations on entities (numbers sum) | 65 | | System with N Components Multiple Composition | Same as *System with N Components* but with mixture of other components | 66 | 67 | # Running 68 | 69 | Just call `Benchmark.sh` from terminal. 70 | 71 | Command line args: 72 | 73 | | arg | description | sample | 74 | |------------|:----------------------------------------:|------------------------------------------------| 75 | | benchmark | allow to specify single benchmark to run | `benchmarks=CreateEmptyEntities,Add1Component` | 76 | | benchmarks | allow to specify benchmarks to run | `benchmark=CreateEmptyEntities` | 77 | | contexts | allow to specify contexts to run | `contexts=Morpeh,Fennecs,...` | 78 | | --list | prints all benchmarks name | `--list` | 79 | 80 | > Since all comparisons is made by string contains you can simply write something like `contexts=Morpeh` 81 | > instead of `context=MorpehContext` 82 | > and `benchmarks=With1,With2` to launch subset of benchmarks. 83 | > Selected benchmarks and contexts will be logged to console. 84 | > BUT benchmark arg requires exact name match with those printed with `--list` 85 | 86 | # Contribution 87 | 88 | - Fork 89 | - Implement 90 | - Create PR 91 | 92 | # Problems 93 | 94 | 1. Because of nature of BenchmarkDotNet there's sequential iteration of creating entities happening. 95 | This leads to case where, for example we're creating 100k entities in benchmark, it's properly cleared 96 | in Setup and Cleanup but benchmark itself will be called multiple times which will lead to creating 100k entities, 97 | then another 100k and in some cases lead to millions of entities in the world which can affect performance of creation 98 | and deletion on certain ECS implementations. 99 | 2. System benchmarks which uses *Padding* property produces up to 1.100.000 entities each because of logic of padding 100 | generation. It affects runs duration but for now i'm not sure about correct way do fix that (maybe keep entire 101 | entities count up to *EntityCount* so it'll not affect speed, but it'll reduce actual entity count to about 9.9k so archetype 102 | ecs implementation will gain significant boost). 103 | 3. Because some framework deleting entity on delete last components there are differences in behaviours in tests and 104 | benchmarks. 105 | For example **RemoveComponent** benchmark will work faster with Arch and Fennecs because they're not deleting entity. 106 | Because of that special property called `DeletesEntityOnLastComponentDeletion` is required to be implemented in each 107 | context. 108 | -------------------------------------------------------------------------------- /Raw_Runner/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Reflection; 6 | using Benchmark; 7 | // using Benchmark.Generated; 8 | using BenchmarkDotNet.Attributes; 9 | 10 | const bool IS_ITERATIVE_RUN = true; 11 | const int ITERATIONS_OR_MILLISECONDS = 1_000; 12 | const int ENTITY_COUNT = 1_000_000; 13 | 14 | RunBenchType(typeof(SystemWith3Components_ArrayECSContext)); 15 | return; 16 | 17 | 18 | Console.WriteLine("use this for testing and debugging\n\n"); 19 | 20 | var results = new Dictionary(); 21 | foreach (var (bench, impls) in BenchMap.Runs) { 22 | Console.WriteLine(bench.Name + " bechnmark runs...\n"); 23 | 24 | var res = new double[impls.Length]; 25 | for (var i = 0; i < impls.Length; i++) { 26 | res[i] = RunBenchType(impls[i]); 27 | } 28 | results[bench] = res; 29 | 30 | Console.WriteLine(); 31 | } 32 | 33 | PrintResults(results); 34 | 35 | Console.WriteLine("finished successfully"); 36 | return; 37 | 38 | double RunBenchType(Type type) { 39 | if (IS_ITERATIVE_RUN) return RunBenchIterations(type); 40 | return RunBenchDuration(type); 41 | } 42 | 43 | 44 | double RunBenchIterations(Type type) { 45 | Console.Write($"bench {type.Name} ... "); 46 | var b = (IBenchmark)Activator.CreateInstance(type); 47 | InjectParameters(b); 48 | b.GlobalSetup(); 49 | 50 | { // warmup 51 | b.IterationSetup(); 52 | b.Run(); 53 | b.IterationCleanup(); 54 | } 55 | 56 | var n = 0; 57 | var t = 0.0; 58 | while (n < ITERATIONS_OR_MILLISECONDS) { 59 | b.IterationSetup(); 60 | var sw = Stopwatch.StartNew(); 61 | b.Run(); 62 | t += sw.Elapsed.TotalMilliseconds; 63 | n++; 64 | b.IterationCleanup(); 65 | } 66 | 67 | b.GlobalCleanup(); 68 | 69 | Console.WriteLine($"did {n} iterations for {t / n} ms average"); 70 | return t / n; 71 | } 72 | 73 | double RunBenchDuration(Type type) { 74 | var b = (IBenchmark)Activator.CreateInstance(type); 75 | InjectParameters(b); 76 | b.GlobalSetup(); 77 | 78 | { // warmup 79 | b.IterationSetup(); 80 | b.Run(); 81 | b.IterationCleanup(); 82 | } 83 | 84 | var n = 0; 85 | double t = 0.0; 86 | var _ = Stopwatch.StartNew(); 87 | while (_.ElapsedMilliseconds < ITERATIONS_OR_MILLISECONDS) { 88 | b.IterationSetup(); 89 | var sw = Stopwatch.StartNew(); 90 | b.Run(); 91 | t += sw.Elapsed.TotalMilliseconds; 92 | n++; 93 | b.IterationCleanup(); 94 | } 95 | 96 | b.GlobalCleanup(); 97 | 98 | Console.WriteLine($"bench {type.Name} did {n} iterations for {t / n} ms average"); 99 | return n; 100 | } 101 | 102 | static void InjectParameters(IBenchmark benchmark) { 103 | benchmark.EntityCount = ENTITY_COUNT; 104 | 105 | var properties = benchmark.GetType() 106 | .GetProperties(BindingFlags.Instance | BindingFlags.Public) 107 | .Where(p => p.Name != nameof(IBenchmark.EntityCount)) 108 | .Select(p => (p, p.GetCustomAttribute())) 109 | .Where(kv => kv.Item2 != null) 110 | .ToArray(); 111 | foreach (var (property, attribute) in properties) { 112 | property.SetValue(benchmark, attribute.Values[0]); 113 | } 114 | } 115 | 116 | static void PrintResults(Dictionary data) { 117 | // Determine the column widths 118 | int typeColumnWidth = data.Keys.Max(k => k.Name.Length) + 2; 119 | var ctxs = BenchMap.Contexts.Keys.ToArray(); 120 | int[] valueColumnWidths = Enumerable 121 | .Range(0, data.Values.Max(v => v.Length)) 122 | .Select(i => Math.Max( 123 | ctxs[i].Name.Length + 2, 124 | data.Values.Where(v => i < v.Length).Max(v => $"{v[i].ToString(IS_ITERATIVE_RUN ? "F4" : "N0")} {(IS_ITERATIVE_RUN ? "ms" : "n")} ".Length) 125 | )) 126 | .ToArray(); 127 | 128 | // Print header 129 | Console.Write("Type".PadRight(typeColumnWidth)); 130 | for (int i = 0; i < ctxs.Length; i++) { 131 | Console.Write("|"); 132 | Console.Write($"{ctxs[i].Name} ".PadLeft(valueColumnWidths[i])); 133 | } 134 | Console.WriteLine(); 135 | 136 | // Print separator 137 | Console.WriteLine(new string('-', typeColumnWidth + valueColumnWidths.Sum() + valueColumnWidths.Length * 2 - 1)); 138 | 139 | // Print rows 140 | foreach (var kvp in data) 141 | { 142 | Console.Write(kvp.Key.Name.PadRight(typeColumnWidth)); 143 | for (int i = 0; i < valueColumnWidths.Length; i++) 144 | { 145 | Console.Write("|"); 146 | if (i < kvp.Value.Length) 147 | Console.Write($"{kvp.Value[i].ToString(IS_ITERATIVE_RUN ? "F4" : "N0")} {(IS_ITERATIVE_RUN ? "ms" : "n")} ".PadLeft(valueColumnWidths[i])); 148 | else 149 | Console.Write(new string(' ', valueColumnWidths[i] + 1)); 150 | } 151 | Console.WriteLine(); 152 | } 153 | } 154 | //*/ 155 | -------------------------------------------------------------------------------- /Raw_Runner/Raw_Runner.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | 12 7 | disable 8 | disable 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Scellecs.Morpeh.Workaround/Scellecs.Morpeh.Workaround.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | 12 6 | disable 7 | enable 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Scellecs.Morpeh.Workaround/WorldExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Scellecs.Morpeh.Workaround; 2 | 3 | public static class WorldExtensions 4 | { 5 | public static int EntityCount(this World world) 6 | { 7 | return world.entitiesCount; 8 | } 9 | } --------------------------------------------------------------------------------