Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/Ecs.CSharp.Benchmark/Categories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ internal static class Categories
public const string LeopotamEcsLite = "Leopotam.EcsLite";
public const string MonoGameExtended = "MonoGame.Extended";
public const string Myriad = "Myriad.ECS";
public const string PewPewEcs = "PewPew.Ecs";
public const string RelEcs = "RelEcs";
public const string SveltoECS = "Svelto.ECS";
public const string Morpeh = "Morpeh";
Expand Down
45 changes: 45 additions & 0 deletions source/Ecs.CSharp.Benchmark/Contexts/PewPewEcsBaseContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using PewPew.Ecs.Core;
using PewPew.Ecs.Hybrid;

namespace Ecs.CSharp.Benchmark
{
public struct PPComponent1 : IComponent
{
public int Value;
}

public struct PPComponent2 : IComponent
{
public int Value;
}

public struct PPComponent3 : IComponent
{
public int Value;
}
}

namespace Ecs.CSharp.Benchmark.Contexts
{

public class PewPewEcsBaseContext
{
public HybridWorld HybridWorld { get; }

public PewPewEcsBaseContext()
{

}

public PewPewEcsBaseContext(int entityCount)
{
HybridWorld = WorldFactory.Shared.CreateHybridWorld(c => c.MaxEntitiesCount = entityCount);
}

public PewPewEcsBaseContext(int entityCount, int entityPadding)
{
HybridWorld = WorldFactory.Shared.CreateHybridWorld(c => c.MaxEntitiesCount = entityCount * entityPadding + entityCount);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using BenchmarkDotNet.Attributes;
using Ecs.CSharp.Benchmark.Contexts;
using PewPew.Ecs.Core;
using PewPew.Ecs.Hybrid;

namespace Ecs.CSharp.Benchmark
{
public partial class CreateEntityWithOneComponent
{
[BenchmarkCategory(Categories.PewPewEcs)]
[Benchmark]
public void PewPewEcs()
{
HybridWorld world = WorldFactory.Shared.CreateHybridWorld(c => c.MaxEntitiesCount = EntityCount);
world.InitComponent<PPComponent1>();

for (int i = 0; i < EntityCount; ++i)
{
EntityId entityId = world.CreateEntityId();
world.AddComponent<PPComponent1>(entityId);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using BenchmarkDotNet.Attributes;
using Ecs.CSharp.Benchmark.Contexts;
using PewPew.Ecs.Core;
using PewPew.Ecs.Hybrid;

namespace Ecs.CSharp.Benchmark
{
public partial class CreateEntityWithThreeComponents
{
[BenchmarkCategory(Categories.PewPewEcs)]
[Benchmark]
public void PewPewEcs()
{
HybridWorld world = WorldFactory.Shared.CreateHybridWorld(c => c.MaxEntitiesCount = EntityCount);
world.InitStaticArchetype<PPComponent1, PPComponent2, PPComponent3>();

var archetype = world.GetStaticArchetype<PPComponent1, PPComponent2, PPComponent3>();

for (int i = 0; i < EntityCount; ++i)
{
EntityId entityId = world.CreateEntityId();
archetype.Create(entityId);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using BenchmarkDotNet.Attributes;
using Ecs.CSharp.Benchmark.Contexts;
using PewPew.Ecs.Core;
using PewPew.Ecs.Hybrid;

namespace Ecs.CSharp.Benchmark
{
public partial class CreateEntityWithTwoComponents
{
[BenchmarkCategory(Categories.PewPewEcs)]
[Benchmark]
public void PewPewEcs()
{
HybridWorld world = WorldFactory.Shared.CreateHybridWorld(c => c.MaxEntitiesCount = EntityCount);
world.InitStaticArchetype<PPComponent1, PPComponent2>();

var archetype = world.GetStaticArchetype<PPComponent1, PPComponent2>();

for (int i = 0; i < EntityCount; ++i)
{
EntityId entityId = world.CreateEntityId();
archetype.Create(entityId);
}
}
}
}
14 changes: 8 additions & 6 deletions source/Ecs.CSharp.Benchmark/Ecs.CSharp.Benchmark.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">

<PropertyGroup>
<LangVersion>latest</LangVersion>
<TargetFramework>net8.0</TargetFramework>
Expand All @@ -11,8 +11,9 @@
<AnalysisLevel>latest</AnalysisLevel>
<RunAnalyzersDuringBuild>true</RunAnalyzersDuringBuild>
<RunAnalyzersDuringLiveAnalysis>true</RunAnalyzersDuringLiveAnalysis>
<NoWarn>$(NoWarn);NETSDK1206</NoWarn>

<NoWarn>$(NoWarn);NETSDK1206;CA1515;CA1815;CA1051</NoWarn>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

<DefineConstants Condition="'$(CheckCacheMisses)' == 'true'">CHECK_CACHE_MISSES</DefineConstants>
</PropertyGroup>

Expand All @@ -21,6 +22,7 @@
<PackageReference Include="Arch.System.SourceGenerator" Version="1.2.1" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0" PrivateAssets="all" />
<PackageReference Include="Myriad.ECS" Version="49.0.0" />
<PackageReference Include="PewPew.Ecs" Version="1.2.1" />
<PackageReference Include="Roslynator.Analyzers" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Roslynator.CodeAnalysis.Analyzers" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Roslynator.Formatting.Analyzers" Version="4.10.0" PrivateAssets="all" />
Expand All @@ -38,11 +40,11 @@
<PackageReference Include="DefaultEcs.Analyzer" Version="0.17.0" PrivateAssets="all" />

<PackageReference Include="fennecs" Version="0.1.1-beta" />

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

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

<PackageReference Include="MonoGame.Extended.Entities" Version="3.8.0" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" />

Expand All @@ -58,5 +60,5 @@
<PackageReference Include="Svelto.Common" Version="3.3.2" />
<PackageReference Include="Flecs.NET.Release" Version="3.2.11" />
</ItemGroup>

</Project>
77 changes: 77 additions & 0 deletions source/Ecs.CSharp.Benchmark/SystemWithOneComponent/PewPewEcs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Numerics;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using Ecs.CSharp.Benchmark.Contexts;
using PewPew.Ecs.Core;
using PewPew.Ecs.Hybrid;

namespace Ecs.CSharp.Benchmark
{
public partial class SystemWithOneComponent
{
[Context]
private readonly PewPewEcsContext _pewPewEcsContext;

[BenchmarkCategory(Categories.PewPewEcs)]
[Benchmark]
public void PewPewEcs() =>
_pewPewEcsContext.HybridWorld.ExecuteQueryWithoutId<OneComponentsQuery, PPComponent1>(_pewPewEcsContext.Query);

[BenchmarkCategory(Categories.PewPewEcs)]
[Benchmark]
public void PewPewEcs_Simd() =>
_pewPewEcsContext.HybridWorld.ExecuteBatchQuery<OneComponentsBatchQuery, PPComponent1>(_pewPewEcsContext.BatchQuery);

private sealed class PewPewEcsContext : PewPewEcsBaseContext
{
public OneComponentsQuery Query;
public OneComponentsBatchQuery BatchQuery;

public PewPewEcsContext(int entityCount, int entityPadding) : base(entityCount, entityPadding)
{
Query = default;

HybridWorld.InitComponent<PPComponent1>();

for (int i = 0; i < entityCount; ++i)
{
for (int j = 0; j < entityPadding; ++j)
{
HybridWorld.CreateEntityId();
}

EntityId entityId = HybridWorld.CreateEntityId();
HybridWorld.AddComponent<PPComponent1>(entityId);
}
}
}

internal struct OneComponentsQuery : IQueryWithoutId<PPComponent1>
{
public void Update(ref PPComponent1 component1)
{
++component1.Value;
}
}

internal struct OneComponentsBatchQuery : IBatchQuery<PPComponent1>
{
public void BatchUpdate(Span<PPComponent1> component1)
{
int vectorCount = Vector<int>.Count; // 8
int length = component1.Length - (component1.Length % vectorCount);

Span<Vector<int>> vectors1 = MemoryMarshal.Cast<PPComponent1, Vector<int>>(component1.Slice(0, length));

for (int i = 0; i < vectors1.Length; i++)
vectors1[i] += Vector<int>.One;

for (int i = length; i < component1.Length; i++)
component1[i].Value++;
}

public void SparseUpdate(ref PPComponent1 component1) => ++component1.Value;
}
}
}
131 changes: 131 additions & 0 deletions source/Ecs.CSharp.Benchmark/SystemWithThreeComponents/PewPewEcs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using System;
using System.Numerics;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using Ecs.CSharp.Benchmark.Contexts;
using PewPew.Ecs.Core;
using PewPew.Ecs.Filters;
using PewPew.Ecs.Hybrid;

namespace Ecs.CSharp.Benchmark
{
public partial class SystemWithThreeComponents
{
[Context]
private readonly PewPewEcsContext _pewPewEcsContext;

[BenchmarkCategory(Categories.PewPewEcs)]
[Benchmark]
public void PewPewEcs() =>
_pewPewEcsContext.HybridWorld.ExecuteQueryWithoutId<ThreeComponentsQuery, PPComponent1, PPComponent2, PPComponent3>(
_pewPewEcsContext.FilterDefinition,
_pewPewEcsContext.Query);

[BenchmarkCategory(Categories.PewPewEcs)]
[Benchmark]
public void PewPewEcs_Simd() =>
_pewPewEcsContext.HybridWorld.ExecuteBatchQuery<ThreeComponentsBatchQuery, PPComponent1, PPComponent2, PPComponent3>(
_pewPewEcsContext.FilterDefinition,
_pewPewEcsContext.BatchQuery);

private sealed class PewPewEcsContext : PewPewEcsBaseContext
{
public FilterDefinition FilterDefinition;

public ThreeComponentsQuery Query;
public ThreeComponentsBatchQuery BatchQuery;

public PewPewEcsContext(int entityCount, int entityPadding) : base(entityCount, entityPadding)
{
HybridWorld.InitThreeComponentArchetype();

Query = default;
BatchQuery = default;

FilterDefinition = new FilterDefinition()
.With<PPComponent1>()
.With<PPComponent2>()
.With<PPComponent3>();

ThreeComponentArchetype archetype = HybridWorld.GetThreeComponentArchetype();

for (int i = 0; i < entityCount; ++i)
{
for (int j = 0; j < entityPadding; ++j)
{
EntityId paddingEntityId = HybridWorld.CreateEntityId();
switch (j % 3)
{
case 0:
HybridWorld.AddComponent<PPComponent1>(paddingEntityId);
break;

case 1:
HybridWorld.AddComponent<PPComponent2>(paddingEntityId);
break;

case 2:
HybridWorld.AddComponent<PPComponent3>(paddingEntityId);
break;
}
}

EntityId entityId = HybridWorld.CreateEntityId();

ThreeComponent components = archetype.Add(entityId);
components.Component1 = new PPComponent1 { Value = 0 };
components.Component2 = new PPComponent2 { Value = 1 };
components.Component3 = new PPComponent3 { Value = 1 };
}
}
}
}

[PewPew.Ecs.Hybrid.Archetype]
public ref struct ThreeComponent
{
public ref PPComponent1 Component1;
public ref PPComponent2 Component2;
public ref PPComponent3 Component3;

public ThreeComponent(ref PPComponent1 component1, ref PPComponent2 component2, ref PPComponent3 component3)
{
Component1 = ref component1;
Component2 = ref component2;
Component3 = ref component3;
}
}

public struct ThreeComponentsQuery : IQueryWithoutId<PPComponent1, PPComponent2, PPComponent3>
{
public void Update(ref PPComponent1 component1, ref PPComponent2 component2, ref PPComponent3 component3)
{
component1.Value += component2.Value + component3.Value;
}
}

public struct ThreeComponentsBatchQuery : IBatchQuery<PPComponent1, PPComponent2, PPComponent3>
{
public void BatchUpdate(Span<PPComponent1> component1, Span<PPComponent2> component2, Span<PPComponent3> component3)
{
int vectorCount = Vector<int>.Count; // 8
int length = component1.Length - (component1.Length % vectorCount);

Span<Vector<int>> vectors1 = MemoryMarshal.Cast<PPComponent1, Vector<int>>(component1.Slice(0, length));
Span<Vector<int>> vectors2 = MemoryMarshal.Cast<PPComponent2, Vector<int>>(component2.Slice(0, length));
Span<Vector<int>> vectors3 = MemoryMarshal.Cast<PPComponent3, Vector<int>>(component3.Slice(0, length));

for (int i = 0; i < vectors1.Length; i++)
vectors1[i] += vectors2[i] + vectors3[i];

for (int i = length; i < component1.Length; i++)
component1[i].Value += component2[i].Value + component3[i].Value;
}

public void SparseUpdate(ref PPComponent1 component1, ref PPComponent2 component2, ref PPComponent3 component3)
{
component1.Value += component2.Value + component3.Value;
}
}

}
Loading
Loading