Skip to content

Commit 2f4768f

Browse files
authored
Featrue/0.4.3.3 (#5)
* ActorContext to sparse pages * ActorRelations refactor * Add more benchmarks * Cleanup
1 parent 3034362 commit 2f4768f

82 files changed

Lines changed: 1658 additions & 1042 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Directory.Packages.props

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,26 @@
11
<Project>
2-
<PropertyGroup>
3-
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4-
<CentralPackageVersionOverrideEnabled>true</CentralPackageVersionOverrideEnabled>
5-
</PropertyGroup>
6-
7-
<ItemGroup>
8-
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0"/>
9-
</ItemGroup>
10-
11-
<ItemGroup>
12-
<PackageVersion Include="MonoGame.Framework.DesktopGL" Version="3.8.4.1"/>
13-
</ItemGroup>
14-
15-
<ItemGroup>
16-
<PackageVersion Include="DefaultEcs" Version="0.17.2"/>
17-
</ItemGroup>
18-
19-
<ItemGroup>
20-
<PackageVersion Include="AutoFixture.Xunit2" Version="4.18.1"/>
21-
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8"/>
22-
<PackageVersion Include="FluentAssertions" Version="8.8.0"/>
23-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1"/>
24-
<PackageVersion Include="Moq" Version="4.20.72"/>
25-
<PackageVersion Include="xunit" Version="2.9.3"/>
26-
<PackageVersion Include="JunitXml.TestLogger" Version="7.1.0"/>
27-
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5"/>
28-
<PackageVersion Include="coverlet.msbuild" Version="6.0.4"/>
29-
<PackageVersion Include="coverlet.collector" Version="6.0.4"/>
30-
</ItemGroup>
2+
<PropertyGroup>
3+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4+
<CentralPackageVersionOverrideEnabled>true</CentralPackageVersionOverrideEnabled>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageVersion Include="Friflo.Engine.ECS" Version="3.4.2" />
8+
<PackageVersion Include="DefaultEcs" Version="0.17.2" />
9+
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
10+
</ItemGroup>
11+
<ItemGroup>
12+
<PackageVersion Include="MonoGame.Framework.DesktopGL" Version="3.8.4.1" />
13+
</ItemGroup>
14+
<ItemGroup>
15+
<PackageVersion Include="AutoFixture.Xunit2" Version="4.18.1" />
16+
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
17+
<PackageVersion Include="FluentAssertions" Version="8.8.0" />
18+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
19+
<PackageVersion Include="Moq" Version="4.20.72" />
20+
<PackageVersion Include="xunit" Version="2.9.3" />
21+
<PackageVersion Include="JunitXml.TestLogger" Version="7.1.0" />
22+
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
23+
<PackageVersion Include="coverlet.msbuild" Version="6.0.4" />
24+
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
25+
</ItemGroup>
3126
</Project>

src/Hexecs.Benchmarks.City/Common/Visibles/VisibleSystem.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using Hexecs.Benchmarks.Map.Common.Positions;
33
using Hexecs.Benchmarks.Map.Terrains;
44
using Hexecs.Benchmarks.Map.Utils;
5-
using Hexecs.Benchmarks.Map.Utils.Sprites;
65
using Hexecs.Threading;
76
using Hexecs.Worlds;
87

src/Hexecs.Benchmarks.City/Terrains/Commands/Generate/GenerateTerrainHandler.cs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using Hexecs.Actors.Pipelines;
2+
using Hexecs.Benchmarks.Map.Common.Positions;
23
using Hexecs.Benchmarks.Map.Terrains.Assets;
34
using Hexecs.Benchmarks.Map.Terrains.ValueTypes;
5+
using Hexecs.Benchmarks.Map.Utils;
46
using Hexecs.Pipelines;
57

68
namespace Hexecs.Benchmarks.Map.Terrains.Commands.Generate;
@@ -9,7 +11,9 @@ internal sealed class GenerateTerrainHandler : ActorCommandHandler<GenerateTerra
911
{
1012
private readonly TerrainSettings _settings;
1113

12-
public GenerateTerrainHandler(ActorContext context, TerrainSettings settings) : base(context)
14+
public GenerateTerrainHandler(
15+
ActorContext context,
16+
TerrainSettings settings) : base(context)
1317
{
1418
_settings = settings;
1519
}
@@ -28,17 +32,20 @@ public override Result Handle(in GenerateTerrainCommand terrainCommand)
2832
for (var x = 0; x < width; x++)
2933
{
3034
var args = Args.Rent(nameof(Point), new Point(x, y));
31-
var actor = x switch
35+
if (x is > 45 and < 55) // river
3236
{
33-
// river
34-
> 45 and < 55 => Context.BuildActor<Terrain>(river, args
35-
.Set(nameof(Terrain.Elevation), Elevation.FromValue(-10))
36-
.Set(nameof(Terrain.Moisture), Moisture.FromValue(35))),
37-
// urban concrete
38-
< 10 when y < 10 => Context.BuildActor<Terrain>(urbanConcrete, args),
39-
// just ground
40-
_ => Context.BuildActor<Terrain>(ground, args)
41-
};
37+
Context.BuildActor<Terrain>(river,
38+
args.Set(nameof(Terrain.Elevation), Elevation.FromValue(-10))
39+
.Set(nameof(Terrain.Moisture), Moisture.FromValue(35)));
40+
}
41+
else if (x < 10 && y < 10) // urban concrete
42+
{
43+
Context.BuildActor<Terrain>(urbanConcrete, args);
44+
}
45+
else // just ground
46+
{
47+
Context.BuildActor<Terrain>(ground, args);
48+
}
4249
}
4350
}
4451

src/Hexecs.Benchmarks.City/Terrains/TerrainDrawSystem.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using Hexecs.Benchmarks.Map.Common.Positions;
33
using Hexecs.Benchmarks.Map.Common.Visibles;
44
using Hexecs.Benchmarks.Map.Utils;
5-
using Hexecs.Benchmarks.Map.Utils.Sprites;
65
using Hexecs.Worlds;
76
using Microsoft.Xna.Framework.Graphics;
87

src/Hexecs.Benchmarks.City/Terrains/TerrainInstaller.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
using Hexecs.Benchmarks.Map.Common.Positions;
12
using Hexecs.Benchmarks.Map.Terrains.Assets;
23
using Hexecs.Benchmarks.Map.Terrains.Commands.Generate;
34
using Hexecs.Configurations;
45
using Hexecs.Dependencies;
56
using Hexecs.Worlds;
67
using Microsoft.Xna.Framework.Content;
7-
using Microsoft.Xna.Framework.Graphics;
88

99
namespace Hexecs.Benchmarks.Map.Terrains;
1010

@@ -23,7 +23,7 @@ public static ActorContextBuilder AddTerrain(this ActorContextBuilder builder)
2323
builder.CreateCommandHandler<GenerateTerrainHandler>();
2424

2525
builder.CreateDrawSystem<TerrainDrawSystem>();
26-
26+
2727
return builder;
2828
}
2929

@@ -32,6 +32,11 @@ public static WorldBuilder UseTerrain(this WorldBuilder builder)
3232
builder
3333
.UseAddAssetSource(new TerrainAssetSource());
3434

35+
builder
36+
.UseScoped(ctx => new ActorDictionary<Point, Position>(
37+
context: ctx.GetRequiredService<ActorContext>(),
38+
keyExtractor: terrain => terrain.Grid));
39+
3540
builder
3641
.UseSingleton(ctx => new TerrainSpriteAtlas(
3742
contentManager: ctx.GetRequiredService<ContentManager>(),

src/Hexecs.Benchmarks.City/Terrains/TerrainSpriteAtlas.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using Hexecs.Benchmarks.Map.Terrains.ValueTypes;
22
using Hexecs.Benchmarks.Map.Utils.Sprites;
33
using Microsoft.Xna.Framework.Content;
4-
using Microsoft.Xna.Framework.Graphics;
54

65
namespace Hexecs.Benchmarks.Map.Terrains;
76

src/Hexecs.Benchmarks.City/Utils/PointExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ namespace Hexecs.Benchmarks.Map.Utils;
22

33
public static class PointExtensions
44
{
5-
public static void GetNeighborPoints(int x, int y, ref Span<Point> neighbors)
5+
public static void GetNeighborPoints(this in Point point, ref Span<Point> neighbors)
66
{
7+
var x = point.X;
8+
var y = point.Y;
9+
710
neighbors[0] = new Point(x - 1, y);
811
neighbors[1] = new Point(x + 1, y);
912
neighbors[2] = new Point(x, y - 1);
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
using System.Runtime.CompilerServices;
2+
using Friflo.Engine.ECS;
3+
using Hexecs.Benchmarks.Mocks.ActorComponents;
4+
using Hexecs.Worlds;
5+
using World = Hexecs.Worlds.World;
6+
7+
namespace Hexecs.Benchmarks.Actors;
8+
9+
// BenchmarkDotNet v0.15.8, Windows 11 (10.0.22621.4317/22H2/2022Update/SunValley2)
10+
// Intel Xeon CPU E5-2697 v3 2.60GHz, 2 CPU, 56 logical and 28 physical cores
11+
// .NET SDK 10.0.100
12+
// [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v3
13+
// .NET 10.0 : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v3
14+
//
15+
// Job=.NET 10.0 Runtime=.NET 10.0
16+
//
17+
// | Method | Count | Mean | Ratio | Allocated | Alloc Ratio |
18+
// |----------------- |------- |----------:|------:|----------:|------------:|
19+
// | Hexecs_Is | 10000 | 20.42 us | 0.96 | - | NA |
20+
// | Hexecs_Has | 10000 | 21.19 us | 1.00 | - | NA |
21+
// | Hexecs_Reference | 10000 | 24.30 us | 1.15 | - | NA |
22+
// | FriFlo_Has | 10000 | 40.28 us | 1.90 | - | NA |
23+
// | DefaultEcs_Has | 10000 | 73.24 us | 3.46 | - | NA |
24+
// | | | | | | |
25+
// | Hexecs_Is | 100000 | 204.98 us | 0.94 | - | NA |
26+
// | Hexecs_Has | 100000 | 219.12 us | 1.00 | - | NA |
27+
// | Hexecs_Reference | 100000 | 251.83 us | 1.15 | - | NA |
28+
// | FriFlo_Has | 100000 | 409.48 us | 1.87 | - | NA |
29+
// | DefaultEcs_Has | 100000 | 712.00 us | 3.25 | - | NA |
30+
//
31+
// ------------------------------------------------------------------------------------
32+
//
33+
// BenchmarkDotNet v0.15.8, macOS Tahoe 26.2 (25C56) [Darwin 25.2.0]
34+
// Apple M3 Max, 1 CPU, 16 logical and 16 physical cores
35+
// .NET SDK 10.0.101
36+
// [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a
37+
// .NET 10.0 : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a
38+
//
39+
// Job=.NET 10.0 Runtime=.NET 10.0
40+
//
41+
// | Method | Mean | Ratio | Allocated | Alloc Ratio |
42+
// |----------------- |----------:|------:|----------:|------------:|
43+
// | Hexecs_Is | 12.76 us | 0.93 | - | NA |
44+
// | Hexecs_Has | 13.79 us | 1.00 | - | NA |
45+
// | Hexecs_Reference | 15.44 us | 1.12 | - | NA |
46+
// | DefaultEcs_Has | 25.32 us | 1.84 | - | NA |
47+
// | | | | | |
48+
// | Hexecs_Is | 127.64 us | 0.92 | - | NA |
49+
// | Hexecs_Has | 139.17 us | 1.00 | - | NA |
50+
// | Hexecs_Reference | 155.12 us | 1.11 | - | NA |
51+
// | DefaultEcs_Has | 255.36 us | 1.83 | - | NA |
52+
53+
[SimpleJob(RuntimeMoniker.Net10_0)]
54+
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
55+
[MeanColumn, MemoryDiagnoser]
56+
[HideColumns("Job", "Error", "StdDev", "Median", "RatioSD")]
57+
[JsonExporterAttribute.Full]
58+
[JsonExporterAttribute.FullCompressed]
59+
[BenchmarkCategory("Actors")]
60+
public class ActorCheckComponentExistsBenchmark
61+
{
62+
[Params(10_000, 100_000)] public int Count;
63+
64+
private ActorContext _context = null!;
65+
private DefaultEcs.World _defaultWorld = null!;
66+
private EntityStore _frifloWorld = null!;
67+
private ArchetypeQuery _frifloAllEntitiesQuery = null!;
68+
private World _world = null!;
69+
70+
[Benchmark(Baseline = true)]
71+
public int Hexecs_Has()
72+
{
73+
var result = 0;
74+
75+
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
76+
foreach (var actor in _context)
77+
{
78+
if (actor.Has<Speed>()) result++;
79+
}
80+
81+
return result;
82+
}
83+
84+
[Benchmark]
85+
public int DefaultEcs_Has()
86+
{
87+
var result = 0;
88+
89+
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
90+
foreach (var entity in _defaultWorld)
91+
{
92+
if (entity.Has<Speed>())
93+
{
94+
result++;
95+
}
96+
}
97+
98+
return result;
99+
}
100+
101+
[Benchmark]
102+
public int FriFlo_Has()
103+
{
104+
var result = 0;
105+
106+
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
107+
foreach (var entity in _frifloAllEntitiesQuery.Entities)
108+
{
109+
if (entity.HasComponent<Speed>())
110+
{
111+
result++;
112+
}
113+
}
114+
115+
return result;
116+
}
117+
118+
[Benchmark]
119+
public int Hexecs_Is()
120+
{
121+
var result = 0;
122+
123+
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
124+
foreach (var actor in _context)
125+
{
126+
if (actor.Is<Speed>(out _))
127+
{
128+
result++;
129+
}
130+
}
131+
132+
return result;
133+
}
134+
135+
[Benchmark]
136+
public int Hexecs_Reference()
137+
{
138+
var result = 0;
139+
140+
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
141+
foreach (var actor in _context)
142+
{
143+
ref var reference = ref actor.TryGetRef<Speed>();
144+
if (!Unsafe.IsNullRef(ref reference))
145+
{
146+
result++;
147+
}
148+
}
149+
150+
return result;
151+
}
152+
153+
[GlobalCleanup]
154+
public void Cleanup()
155+
{
156+
_defaultWorld.Dispose();
157+
_defaultWorld = null!;
158+
159+
_frifloWorld = null!;
160+
161+
_world.Dispose();
162+
_world = null!;
163+
}
164+
165+
[GlobalSetup]
166+
public void Setup()
167+
{
168+
_defaultWorld = new DefaultEcs.World();
169+
_frifloWorld = new EntityStore();
170+
_frifloAllEntitiesQuery = _frifloWorld.Query();
171+
_world = new WorldBuilder().Build();
172+
_context = _world.Actors;
173+
174+
for (var i = 0; i < Count; i++)
175+
{
176+
var actor = _context.CreateActor();
177+
actor.Add(new Attack());
178+
actor.Add(new Defence());
179+
180+
var defaultEntity = _defaultWorld.CreateEntity();
181+
defaultEntity.Set<Attack>();
182+
defaultEntity.Set<Defence>();
183+
184+
var frifloEntity = _frifloWorld.CreateEntity(new Attack(), new Defence());
185+
186+
if (i % 10 != 0) continue;
187+
188+
actor.Add(new Speed());
189+
190+
defaultEntity.Set<Speed>();
191+
frifloEntity.Add(new Speed());
192+
}
193+
}
194+
}

0 commit comments

Comments
 (0)