Skip to content

Commit

Permalink
add Friflo.Engine.ECS multi threaded queries. Added 4 methods: Friflo…
Browse files Browse the repository at this point in the history
…EngineEcs_MultiThread()
  • Loading branch information
friflo authored and Doraku committed Feb 15, 2024
1 parent bdb09ac commit da28d17
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 44 deletions.
30 changes: 25 additions & 5 deletions source/Ecs.CSharp.Benchmark/Contexts/FrifloEngineEcsContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Ecs.CSharp.Benchmark.Contexts.FrifloEngine_Components;
using Friflo.Engine.ECS;

namespace Ecs.CSharp.Benchmark.Contexts
Expand All @@ -23,11 +24,29 @@ internal struct Component3 : IComponent

internal class FrifloEngineEcsBaseContext : IDisposable
{
public EntityStore EntityStore { get; }
protected EntityStore EntityStore { get; }
public readonly ArchetypeQuery<Component1> queryOne;
public readonly ArchetypeQuery<Component1, Component2> queryTwo;
public readonly ArchetypeQuery<Component1, Component2, Component3> queryThree;

public readonly QueryJob<Component1> jobOne;
public readonly QueryJob<Component1, Component2> jobTwo;
public readonly QueryJob<Component1, Component2, Component3> jobThree;
public readonly QueryJob<Component1, Component2> jobTwoWithComposition;

public FrifloEngineEcsBaseContext()

protected FrifloEngineEcsBaseContext()
{
EntityStore = new EntityStore(PidType.UsePidAsId);
ParallelJobRunner runner = new ParallelJobRunner(Environment.ProcessorCount);
EntityStore = new EntityStore(PidType.UsePidAsId) { JobRunner = runner };
queryOne = EntityStore.Query<Component1>();
queryTwo = EntityStore.Query<Component1, Component2>();
queryThree = EntityStore.Query<Component1, Component2, Component3>();

jobOne = queryOne.ForEach(SystemWithOneComponent.FrifloEngineEcsContext.ForEach);
jobTwo = queryTwo.ForEach(SystemWithTwoComponents.FrifloEngineEcsContext.ForEach);
jobThree = queryThree.ForEach(SystemWithThreeComponents.FrifloEngineEcsContext.ForEach);
jobTwoWithComposition = queryTwo.ForEach(SystemWithTwoComponentsMultipleComposition.FrifloEngineEcsContext.ForEach);
}

/// <summary>See padding notes</summary>
Expand All @@ -37,9 +56,9 @@ public FrifloEngineEcsBaseContext()
/// e.g. Params[Params(0, 10)] at <see cref="SystemWithOneComponent.EntityPadding"/>
/// </param>
/// <param name="componentTypes"></param>
public FrifloEngineEcsBaseContext(int entityCount, int padding, ComponentTypes componentTypes)
protected FrifloEngineEcsBaseContext(int entityCount, int padding, ComponentTypes componentTypes) : this()
{
EntityStore = new EntityStore(PidType.UsePidAsId);

EntityStore.EnsureCapacity(entityCount + (padding * entityCount));

Archetype archetype = EntityStore.GetArchetype(componentTypes);
Expand All @@ -57,6 +76,7 @@ public FrifloEngineEcsBaseContext(int entityCount, int padding, ComponentTypes c

public virtual void Dispose()
{
EntityStore.JobRunner?.Dispose();
}
}
}
4 changes: 2 additions & 2 deletions source/Ecs.CSharp.Benchmark/Ecs.CSharp.Benchmark.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@

<PackageReference Include="DefaultEcs" Version="0.17.2" />
<PackageReference Include="DefaultEcs.Analyzer" Version="0.17.0" PrivateAssets="all" />
<PackageReference Include="Friflo.Engine.ECS" Version="1.13.0" />

<PackageReference Include="Friflo.Engine.ECS" Version="1.14.0" />

<PackageReference Include="HypEcs" Version="1.2.1" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@ namespace Ecs.CSharp.Benchmark
{
public partial class SystemWithOneComponent
{
private sealed class FrifloEngineEcsContext : FrifloEngineEcsBaseContext
internal sealed class FrifloEngineEcsContext : FrifloEngineEcsBaseContext
{
public FrifloEngineEcsContext(int entityCount, int padding)
: base(entityCount, padding, ComponentTypes.Get<Component1>())
{ }

internal static void ForEach(Chunk<Component1> component1, ChunkEntities entities)
{
foreach (ref Component1 component in component1.Span)
{
++component.Value;
}
}
}

[Context]
Expand All @@ -23,27 +31,29 @@ public FrifloEngineEcsContext(int entityCount, int padding)
[Benchmark]
public void FrifloEngineEcs_MonoThread()
{
EntityStore world = _frifloEngineEcs.EntityStore;
ArchetypeQuery<Component1> query = world.Query<Component1>();

foreach ((Chunk<Component1> component1, ChunkEntities _) in query.Chunks)
foreach ((Chunk<Component1> component1, ChunkEntities _) in _frifloEngineEcs.queryOne.Chunks)
{
foreach (ref Component1 component in component1.Span)
{
++component.Value;
}
}
}


[BenchmarkCategory(Categories.FrifloEngineEcs)]
[Benchmark]
public void FrifloEngineEcs_MultiThread()
{
_frifloEngineEcs.jobOne.RunParallel();
}

[BenchmarkCategory(Categories.FrifloEngineEcs)]
[Benchmark]
public void FrifloEngineEcs_SIMD_MonoThread()
{
EntityStore world = _frifloEngineEcs.EntityStore;
ArchetypeQuery<Component1> query = world.Query<Component1>();
Vector256<int> add = Vector256.Create<int>(1); // create int[8] vector - all values = 1

foreach ((Chunk<Component1> component1, ChunkEntities _) in query.Chunks)
foreach ((Chunk<Component1> component1, ChunkEntities _) in _frifloEngineEcs.queryOne.Chunks)
{
Span<int> component1Span = component1.AsSpan256<int>(); // Length - multiple of 8
int step = component1.StepSpan256; // step = 8
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,22 @@ namespace Ecs.CSharp.Benchmark
{
public partial class SystemWithThreeComponents
{
private sealed class FrifloEngineEcsContext : FrifloEngineEcsBaseContext
internal sealed class FrifloEngineEcsContext : FrifloEngineEcsBaseContext
{
public FrifloEngineEcsContext(int entityCount, int padding)
: base(entityCount, padding, ComponentTypes.Get<Component1, Component2>())
: base(entityCount, padding, ComponentTypes.Get<Component1, Component2, Component3>())
{ }

internal static void ForEach(Chunk<Component1> component1, Chunk<Component2> component2, Chunk<Component3> component3, ChunkEntities entities)
{
Span<Component1> component1Span = component1.Span;
Span<Component2> component2Span = component2.Span;
Span<Component3> component3Span = component3.Span;
for (int n = 0; n < component1Span.Length; n++)
{
Update(ref component1Span[n], ref component2Span[n], ref component3Span[n]);
}
}
}

[Context]
Expand All @@ -23,10 +34,8 @@ public FrifloEngineEcsContext(int entityCount, int padding)
[Benchmark]
public void FrifloEngineEcs_MonoThread()
{
EntityStore world = _frifloEngineEcs.EntityStore;
ArchetypeQuery<Component1, Component2, Component3> query = world.Query<Component1, Component2, Component3>();

foreach ((Chunk<Component1> component1, Chunk<Component2> component2, Chunk<Component3> component3, ChunkEntities _) in query.Chunks)
foreach ((Chunk<Component1> component1, Chunk<Component2> component2, Chunk<Component3> component3, ChunkEntities _)
in _frifloEngineEcs.queryThree.Chunks)
{
Span<Component1> component1Span = component1.Span;
Span<Component2> component2Span = component2.Span;
Expand All @@ -37,6 +46,13 @@ public void FrifloEngineEcs_MonoThread()
}
}
}

[BenchmarkCategory(Categories.FrifloEngineEcs)]
[Benchmark]
public void FrifloEngineEcs_MultiThread()
{
_frifloEngineEcs.jobThree.RunParallel();
}

private static void Update(ref Component1 c1, ref Component2 c2, ref Component3 c3)
{
Expand All @@ -47,10 +63,8 @@ private static void Update(ref Component1 c1, ref Component2 c2, ref Component3
[Benchmark]
public void FrifloEngineEcs_SIMD_MonoThread()
{
EntityStore world = _frifloEngineEcs.EntityStore;
ArchetypeQuery<Component1, Component2, Component3> query = world.Query<Component1, Component2, Component3>();

foreach ((Chunk<Component1> component1, Chunk<Component2> component2, Chunk<Component3> component3, ChunkEntities _) in query.Chunks)
foreach ((Chunk<Component1> component1, Chunk<Component2> component2, Chunk<Component3> component3, ChunkEntities _)
in _frifloEngineEcs.queryThree.Chunks)
{
Span<int> component1Span = component1.AsSpan256<int>(); // Length - multiple of 8
Span<int> component2Span = component2.AsSpan256<int>(); // Length - multiple of 8
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,21 @@ namespace Ecs.CSharp.Benchmark
{
public partial class SystemWithTwoComponents
{
private sealed class FrifloEngineEcsContext : FrifloEngineEcsBaseContext
internal sealed class FrifloEngineEcsContext : FrifloEngineEcsBaseContext
{
public FrifloEngineEcsContext(int entityCount, int padding)
: base(entityCount, padding, ComponentTypes.Get<Component1, Component2>())
{ }

internal static void ForEach(Chunk<Component1> component1, Chunk<Component2> component2, ChunkEntities entities)
{
Span<Component1> component1Span = component1.Span;
Span<Component2> component2Span = component2.Span;
for (int n = 0; n < component1Span.Length; n++)
{
Update(ref component1Span[n], ref component2Span[n]);
}
}
}

[Context]
Expand All @@ -23,10 +33,7 @@ public FrifloEngineEcsContext(int entityCount, int padding)
[Benchmark]
public void FrifloEngineEcs_MonoThread()
{
EntityStore world = _frifloEngineEcs.EntityStore;
ArchetypeQuery<Component1, Component2> query = world.Query<Component1, Component2>();

foreach ((Chunk<Component1> component1, Chunk<Component2> component2, ChunkEntities _) in query.Chunks)
foreach ((Chunk<Component1> component1, Chunk<Component2> component2, ChunkEntities _) in _frifloEngineEcs.queryTwo.Chunks)
{
Span<Component1> component1Span = component1.Span;
Span<Component2> component2Span = component2.Span;
Expand All @@ -36,6 +43,13 @@ public void FrifloEngineEcs_MonoThread()
}
}
}

[BenchmarkCategory(Categories.FrifloEngineEcs)]
[Benchmark]
public void FrifloEngineEcs_MultiThread()
{
_frifloEngineEcs.jobTwo.RunParallel();
}

private static void Update(ref Component1 c1, ref Component2 c2)
{
Expand All @@ -46,10 +60,8 @@ private static void Update(ref Component1 c1, ref Component2 c2)
[Benchmark]
public void FrifloEngineEcs_SIMD_MonoThread()
{
EntityStore world = _frifloEngineEcs.EntityStore;
ArchetypeQuery<Component1, Component2> query = world.Query<Component1, Component2>();

foreach ((Chunk<Component1> component1, Chunk<Component2> component2, ChunkEntities _) in query.Chunks)
foreach ((Chunk<Component1> component1, Chunk<Component2> component2, ChunkEntities _)
in _frifloEngineEcs.queryTwo.Chunks)
{
Span<int> component1Span = component1.AsSpan256<int>(); // Length - multiple of 8
Span<int> component2Span = component2.AsSpan256<int>(); // Length - multiple of 8
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Ecs.CSharp.Benchmark
{
public partial class SystemWithTwoComponentsMultipleComposition
{
private sealed class FrifloEngineEcsContext : FrifloEngineEcsBaseContext
internal sealed class FrifloEngineEcsContext : FrifloEngineEcsBaseContext
{
private record struct Padding1 : IComponent { }

Expand Down Expand Up @@ -47,6 +47,16 @@ public FrifloEngineEcsContext(int entityCount)
}
}
}

internal static void ForEach(Chunk<Component1> component1, Chunk<Component2> component2, ChunkEntities entities)
{
Span<Component1> component1Span = component1.Span;
Span<Component2> component2Span = component2.Span;
for (int n = 0; n < component1Span.Length; n++)
{
Update(ref component1Span[n], ref component2Span[n]);
}
}
}

[Context]
Expand All @@ -56,10 +66,8 @@ public FrifloEngineEcsContext(int entityCount)
[Benchmark]
public void FrifloEngineEcs_MonoThread()
{
EntityStore world = _frifloEngineEcs.EntityStore;
ArchetypeQuery<Component1, Component2> query = world.Query<Component1, Component2>();

foreach ((Chunk<Component1> component1, Chunk<Component2> component2, ChunkEntities _) in query.Chunks)
foreach ((Chunk<Component1> component1, Chunk<Component2> component2, ChunkEntities _)
in _frifloEngineEcs.queryTwo.Chunks)
{
Span<Component1> component1Span = component1.Span;
Span<Component2> component2Span = component2.Span;
Expand All @@ -69,6 +77,13 @@ public void FrifloEngineEcs_MonoThread()
}
}
}

[BenchmarkCategory(Categories.FrifloEngineEcs)]
[Benchmark]
public void FrifloEngineEcs_MultiThread()
{
_frifloEngineEcs.jobTwoWithComposition.RunParallel();
}

private static void Update(ref Component1 c1, ref Component2 c2)
{
Expand All @@ -79,10 +94,8 @@ private static void Update(ref Component1 c1, ref Component2 c2)
[Benchmark]
public void FrifloEngineEcs_SIMD_MonoThread()
{
EntityStore world = _frifloEngineEcs.EntityStore;
ArchetypeQuery<Component1, Component2> query = world.Query<Component1, Component2>();

foreach ((Chunk<Component1> component1, Chunk<Component2> component2, ChunkEntities _) in query.Chunks)
foreach ((Chunk<Component1> component1, Chunk<Component2> component2, ChunkEntities _)
in _frifloEngineEcs.queryTwo.Chunks)
{
Span<int> component1Span = component1.AsSpan256<int>(); // Length - multiple of 8
Span<int> component2Span = component2.AsSpan256<int>(); // Length - multiple of 8
Expand Down

0 comments on commit da28d17

Please sign in to comment.