GetPool optimisation

GetPool almost 2x faster.
This commit is contained in:
Mikhail 2023-06-27 05:09:41 +08:00
parent 35d71245bc
commit 51b409d5d6
4 changed files with 100 additions and 44 deletions

View File

@ -123,10 +123,10 @@ namespace DCFApixels.DragonECS
foreach (var item in _combined) foreach (var item in _combined)
{ {
EcsMask submask = item.aspect.mask; EcsMask submask = item.aspect.mask;
maskInc.ExceptWith(submask._exc);//удаляю конфликтующие ограничения maskInc.ExceptWith(submask.exc);//удаляю конфликтующие ограничения
maskExc.ExceptWith(submask._inc);//удаляю конфликтующие ограничения maskExc.ExceptWith(submask.inc);//удаляю конфликтующие ограничения
maskInc.UnionWith(submask._inc); maskInc.UnionWith(submask.inc);
maskExc.UnionWith(submask._exc); maskExc.UnionWith(submask.exc);
} }
maskInc.ExceptWith(_exc);//удаляю конфликтующие ограничения maskInc.ExceptWith(_exc);//удаляю конфликтующие ограничения
maskExc.ExceptWith(_inc);//удаляю конфликтующие ограничения maskExc.ExceptWith(_inc);//удаляю конфликтующие ограничения
@ -144,7 +144,7 @@ namespace DCFApixels.DragonECS
var exc = maskExc.ToArray(); var exc = maskExc.ToArray();
Array.Sort(exc); Array.Sort(exc);
mask = new EcsMask(_world.WorldTypeID, inc, exc); mask = new EcsMask(_world.id, inc, exc);
_world = null; _world = null;
_inc = null; _inc = null;
_exc = null; _exc = null;
@ -202,24 +202,23 @@ namespace DCFApixels.DragonECS
[DebuggerTypeProxy(typeof(DebuggerProxy))] [DebuggerTypeProxy(typeof(DebuggerProxy))]
public sealed class EcsMask public sealed class EcsMask
{ {
internal readonly int _worldTypeID; internal readonly int worldID;
/// <summary>Including constraints</summary> /// <summary>Including constraints</summary>
internal readonly int[] _inc; internal readonly int[] inc;
/// <summary>Excluding constraints</summary> /// <summary>Excluding constraints</summary>
internal readonly int[] _exc; internal readonly int[] exc;
internal EcsMask(int worldTypeID, int[] inc, int[] exc) internal EcsMask(int worldID, int[] inc, int[] exc)
{ {
#if DEBUG #if DEBUG
if (worldTypeID == 0) throw new ArgumentException();
CheckConstraints(inc, exc); CheckConstraints(inc, exc);
#endif #endif
_worldTypeID = worldTypeID; this.worldID = worldID;
_inc = inc; this.inc = inc;
_exc = exc; this.exc = exc;
} }
#region Object #region Object
public override string ToString() => CreateLogString(_worldTypeID, _inc, _exc); public override string ToString() => CreateLogString(worldID, inc, exc);
#endregion #endregion
#region Debug utils #region Debug utils
@ -247,10 +246,10 @@ namespace DCFApixels.DragonECS
return false; return false;
} }
#endif #endif
private static string CreateLogString(int worldTypeID, int[] inc, int[] exc) private static string CreateLogString(int worldID, int[] inc, int[] exc)
{ {
#if (DEBUG && !DISABLE_DEBUG) #if (DEBUG && !DISABLE_DEBUG)
string converter(int o) => EcsDebugUtility.GetGenericTypeName(WorldMetaStorage.GetComponentType(worldTypeID, o), 1); string converter(int o) => EcsDebugUtility.GetGenericTypeName(EcsWorld.GetWorld(worldID).AllPools[o].ComponentType, 1);
return $"Inc({string.Join(", ", inc.Select(converter))}) Exc({string.Join(", ", exc.Select(converter))})"; return $"Inc({string.Join(", ", inc.Select(converter))}) Exc({string.Join(", ", exc.Select(converter))})";
#else #else
return $"Inc({string.Join(", ", inc)}) Exc({string.Join(", ", exc)})"; // Release optimization return $"Inc({string.Join(", ", inc)}) Exc({string.Join(", ", exc)})"; // Release optimization
@ -259,22 +258,22 @@ namespace DCFApixels.DragonECS
internal class DebuggerProxy internal class DebuggerProxy
{ {
public readonly Type worldType; public readonly Type worldType;
public readonly int worldTypeID; public readonly int worldID;
public readonly int[] included; public readonly int[] included;
public readonly int[] excluded; public readonly int[] excluded;
public readonly Type[] includedTypes; public readonly Type[] includedTypes;
public readonly Type[] excludedTypes; public readonly Type[] excludedTypes;
public DebuggerProxy(EcsMask mask) public DebuggerProxy(EcsMask mask)
{ {
worldType = WorldMetaStorage.GetWorldType(mask._worldTypeID); worldType = WorldMetaStorage.GetWorldType(mask.worldID);
worldTypeID = mask._worldTypeID; worldID = mask.worldID;
included = mask._inc; included = mask.inc;
excluded = mask._exc; excluded = mask.exc;
Type converter(int o) => WorldMetaStorage.GetComponentType(worldTypeID, o); Type converter(int o) => WorldMetaStorage.GetComponentType(worldID, o);
includedTypes = included.Select(converter).ToArray(); includedTypes = included.Select(converter).ToArray();
excludedTypes = excluded.Select(converter).ToArray(); excludedTypes = excluded.Select(converter).ToArray();
} }
public override string ToString() => CreateLogString(worldTypeID, included, excluded); public override string ToString() => CreateLogString(worldID, included, excluded);
} }
#endregion #endregion
} }
@ -338,8 +337,8 @@ namespace DCFApixels.DragonECS
public Enumerator(EcsReadonlyGroup sourceGroup, EcsMask mask) public Enumerator(EcsReadonlyGroup sourceGroup, EcsMask mask)
{ {
_sourceGroup = sourceGroup.GetEnumerator(); _sourceGroup = sourceGroup.GetEnumerator();
_inc = mask._inc; _inc = mask.inc;
_exc = mask._exc; _exc = mask.exc;
_pools = sourceGroup.World._pools; _pools = sourceGroup.World._pools;
} }
public int Current public int Current

40
src/EcsWorld.cache.cs Normal file
View File

@ -0,0 +1,40 @@
using DCFApixels.DragonECS.Utils;
using System;
namespace DCFApixels.DragonECS
{
public partial class EcsWorld
{
internal readonly struct PoolCache<TPool> : IEcsWorldComponent<PoolCache<TPool>>
where TPool : IEcsPoolImplementation, new()
{
public readonly TPool instance;
public PoolCache(TPool instance) => this.instance = instance;
void IEcsWorldComponent<PoolCache<TPool>>.Init(ref PoolCache<TPool> component, EcsWorld world)
{
component = new PoolCache<TPool>(world.CreatePool<TPool>());
}
void IEcsWorldComponent<PoolCache<TPool>>.OnDestroy(ref PoolCache<TPool> component, EcsWorld world)
{
component = default;
}
}
private TPool CreatePool<TPool>() where TPool : IEcsPoolImplementation, new()
{
int index = WorldMetaStorage.GetPoolID<TPool>(_worldTypeID);
if (index >= _pools.Length)
{
int oldCapacity = _pools.Length;
Array.Resize(ref _pools, _pools.Length << 1);
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
}
if (_pools[index] == _nullPool)
{
var pool = new TPool();
_pools[index] = pool;
pool.OnInit(this, index);
}
return (TPool)_pools[index];
}
}
}

View File

@ -3,6 +3,7 @@ using DCFApixels.DragonECS.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using typecode = System.Int32;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
@ -102,22 +103,10 @@ namespace DCFApixels.DragonECS
#if UNITY_2020_3_OR_NEWER #if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.Preserve] [UnityEngine.Scripting.Preserve]
#endif #endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TPool GetPool<TPool>() where TPool : IEcsPoolImplementation, new() public TPool GetPool<TPool>() where TPool : IEcsPoolImplementation, new()
{ {
int index = WorldMetaStorage.GetPoolID<TPool>(_worldTypeID); return Get<PoolCache<TPool>>().instance;
if (index >= _pools.Length)
{
int oldCapacity = _pools.Length;
Array.Resize(ref _pools, _pools.Length << 1);
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
}
if (_pools[index] == _nullPool)
{
var pool = new TPool();
_pools[index] = pool;
pool.OnInit(this, index);
}
return (TPool)_pools[index];
} }
public TAspect GetAspect<TAspect>() where TAspect : EcsAspect public TAspect GetAspect<TAspect>() where TAspect : EcsAspect
{ {
@ -236,17 +225,17 @@ namespace DCFApixels.DragonECS
public bool IsMatchesMask(EcsMask mask, int entityID) public bool IsMatchesMask(EcsMask mask, int entityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (mask._worldTypeID != _worldTypeID) if (mask.worldID != id)
throw new EcsFrameworkException("The types of the target world of the mask and this world are different."); throw new EcsFrameworkException("The types of the target world of the mask and this world are different.");
#endif #endif
for (int i = 0, iMax = mask._inc.Length; i < iMax; i++) for (int i = 0, iMax = mask.inc.Length; i < iMax; i++)
{ {
if (!_pools[mask._inc[i]].Has(entityID)) if (!_pools[mask.inc[i]].Has(entityID))
return false; return false;
} }
for (int i = 0, iMax = mask._exc.Length; i < iMax; i++) for (int i = 0, iMax = mask.exc.Length; i < iMax; i++)
{ {
if (_pools[mask._exc[i]].Has(entityID)) if (_pools[mask.exc[i]].Has(entityID))
return false; return false;
} }
return true; return true;

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
namespace DCFApixels.DragonECS
{
namespace Internal
{
internal static class EcsTypeCode
{
private static readonly Dictionary<Type, int> _codes = new Dictionary<Type, int>();
private static int _incremetn = 1;
public static int GetCode(Type type)
{
if (!_codes.TryGetValue(type, out int code))
{
code = _incremetn++;
_codes.Add(type, code);
}
return code;
}
public static int Count => _codes.Count;
}
internal static class EcsTypeCodeCache<T>
{
public static readonly int code = EcsTypeCode.GetCode(typeof(T));
}
}
}