sorting pools in query iterator

sorting pools in the iterator. by number of entities from the smallest to the largest.
This commit is contained in:
Mikhail 2024-01-06 00:07:07 +08:00
parent fc167fb28c
commit be2ecb8c07
3 changed files with 361 additions and 17 deletions

View File

@ -1,4 +1,9 @@
using DCFApixels.DragonECS.Internal; //#define sort_1
#define lockSwapCheck
// Зеленый свет, тесты показали идентичную скорость или даже прирост
using DCFApixels.DragonECS.Internal;
using DCFApixels.DragonECS.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -215,6 +220,7 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Mask #region Mask
[DebuggerTypeProxy(typeof(DebuggerProxy))]
public readonly struct EcsMaskBit public readonly struct EcsMaskBit
{ {
private const int BITS = 32; private const int BITS = 32;
@ -228,14 +234,32 @@ namespace DCFApixels.DragonECS
this.chankIndex = chankIndex; this.chankIndex = chankIndex;
this.mask = mask; this.mask = mask;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsMaskBit FromID(int id) public static EcsMaskBit FromID(int id)
{ {
short x = 10;
return new EcsMaskBit(id >> DIV_SHIFT, 1 << (id & MOD_MASK)); //аналогично new EcsMaskBit(id / BITS, 1 << (id % BITS)) но быстрее return new EcsMaskBit(id >> DIV_SHIFT, 1 << (id & MOD_MASK)); //аналогично new EcsMaskBit(id / BITS, 1 << (id % BITS)) но быстрее
} }
public override string ToString() public override string ToString()
{ {
return $"bit({chankIndex}, {mask})"; return $"mask({chankIndex}, {mask}, {BitsUtility.CountBits(mask)})";
}
internal class DebuggerProxy
{
public int chunk;
public uint mask;
public int[] values = Array.Empty<int>();
public string bits;
public DebuggerProxy(EcsMaskBit maskbits)
{
chunk = maskbits.chankIndex;
mask = (uint)maskbits.mask;
BitsUtility.GetBitNumbersNoAlloc(mask, ref values);
for (int i = 0; i < values.Length; i++)
{
values[i] += (chunk) << 5;
}
bits = BitsUtility.ToBitsString(mask, '_', 8);
}
} }
} }
@ -248,6 +272,7 @@ namespace DCFApixels.DragonECS
internal readonly int[] inc; internal readonly int[] inc;
internal readonly int[] exc; internal readonly int[] exc;
public int WorldID => worldID; public int WorldID => worldID;
public EcsWorld World => EcsWorld.GetWorld(worldID);
/// <summary>Including constraints</summary> /// <summary>Including constraints</summary>
public ReadOnlySpan<int> Inc => inc; public ReadOnlySpan<int> Inc => inc;
/// <summary>Excluding constraints</summary> /// <summary>Excluding constraints</summary>
@ -405,24 +430,302 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator() => new Enumerator(_span, mask); public Enumerator GetEnumerator() => new Enumerator(_span, mask);
public ref struct Enumerator
public unsafe ref struct Enumerator
{ {
private ReadOnlySpan<int>.Enumerator _span; private ReadOnlySpan<int>.Enumerator _span;
#if sort_1
private readonly EcsMaskBit[] _incChunckMasks; private readonly EcsMaskBit[] _incChunckMasks;
private readonly EcsMaskBit[] _excChunckMasks; private readonly EcsMaskBit[] _excChunckMasks;
#else
private readonly EcsMaskBit[] _incChunckMasks;
private readonly EcsMaskBit[] _excChunckMasks;
#endif
private readonly int[][] _entitiesComponentMasks; private readonly int[][] _entitiesComponentMasks;
private int minCount = 0;
public Enumerator(EcsSpan span, EcsMask mask)
private static EcsMaskBit* _sortedIncBuffer;
private static EcsMaskBit* _sortedExcBuffer;
private static SparseArray<int> _sp;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe Enumerator(EcsSpan span, EcsMask mask)
{ {
_span = span.GetEnumerator(); _span = span.GetEnumerator();
#if sort_1
_incChunckMasks = mask.incChunckMasks; _incChunckMasks = mask.incChunckMasks;
_excChunckMasks = mask.excChunckMasks; _excChunckMasks = mask.excChunckMasks;
#endif
_entitiesComponentMasks = span.World._entitiesComponentMasks; _entitiesComponentMasks = span.World._entitiesComponentMasks;
#region MyRegion
#region Trash
#if !sort_1
int[] inc = mask.inc;
int[] exc = mask.exc;
int[] counts = mask.World._poolComponentCounts;
if (inc.Length > 1)
{
//if (inc.Length == 2)
//{
// if (counts[inc[0]] > counts[inc[1]])
// {
// int tmp = inc[0];
// inc[0] = inc[1];
// inc[1] = tmp;
// }
// //...
//}
//else
{
//for (int i = 0; i < inc.Length; i++)
//{
// int counti = counts[inc[i]];
// if (counti <= 0)
// {
// _span = ReadOnlySpan<int>.Empty.GetEnumerator();
// goto skip1;
// }
// for (int j = inc.Length - 1; j >= i; j--)
// {
// if (counts[inc[j]] < counti)
// {
// int tmp = inc[j];
// inc[j] = inc[i];
// inc[i] = tmp;
// }
// }
//}
//...
for (int i = 0, n = inc.Length; i < n - 1; i++)
{
//int counti = counts[inc[i]];
//if (counti <= 0)
//{
// _span = ReadOnlySpan<int>.Empty.GetEnumerator();
// goto skip1;
//}
bool noSwaped = true;
for (int j = 0; j < n - i - 1; )
{
ref int j0 = ref inc[j++];
if (counts[j0] > counts[inc[j]])
{
int tmp = inc[j];
inc[j] = j0;
j0 = tmp;
noSwaped = false;
}
}
#if !lockSwapCheck
if (noSwaped)
break;
#endif
}
}
}
skip1:;
if (exc.Length > 1)
{
//if (exc.Length == 2)
//{
// if (counts[exc[0]] < counts[exc[1]])
// {
// int tmp = exc[0];
// exc[0] = inc[1];
// exc[1] = tmp;
// }
// //...
//}
//else
{
//for (int i = 0; i < exc.Length; i++)
//{
// int counti = counts[inc[i]];
// if (counti <= 0)
// {
// _excChunckMasks = ReadOnlySpan<EcsMaskBit>.Empty;
// goto skip2;
// }
// for (int j = exc.Length - 1; j >= i; j--)
// {
// if (counts[exc[j]] > counti)
// {
// int tmp = exc[j];
// exc[j] = exc[i];
// exc[i] = tmp;
// }
// }
//}
//...
for (int i = 0, n = exc.Length; i < n - 1; i++)
{
//int counti = counts[inc[i]];
//if (counti <= 0)
//{
// _excChunckMasks = ReadOnlySpan<EcsMaskBit>.Empty;
// goto skip2;
//}
bool noSwaped = true;
for (int j = 0; j < n - i - 1;)
{
ref int j0 = ref exc[j++];
if (counts[j0] < counts[exc[j]])
{
int tmp = exc[j];
exc[j] = j0;
j0 = tmp;
noSwaped = false;
}
}
#if !lockSwapCheck
if (noSwaped)
break;
#endif
}
}
}
skip2:;
if (_sortedIncBuffer == null)
{
_sortedIncBuffer = UnmanagedArrayUtility.New<EcsMaskBit>(256);
_sortedExcBuffer = UnmanagedArrayUtility.New<EcsMaskBit>(256);
_sp = new SparseArray<int>(32);
}
_sp.Clear();
for (int i = 0, ii = 0; i < inc.Length; i++)
{
//int id = inc[i];
//_sortedIncBuffer[i] = new EcsMaskBit(id >> DIV_SHIFT, 1 << (id & MOD_MASK));
_sortedIncBuffer[i] = EcsMaskBit.FromID(inc[i]);
}
for (int i = 0; i < exc.Length; i++)
{
//int id = inc[i];
//_sortedExcBuffer[i] = new EcsMaskBit(id >> DIV_SHIFT, 1 << (id & MOD_MASK));
_sortedExcBuffer[i] = EcsMaskBit.FromID(exc[i]);
}
EcsMaskBit[] incChunckMasks = mask.incChunckMasks;
EcsMaskBit[] excChunckMasks = mask.excChunckMasks;
//_incChunckMasks = new ReadOnlySpan<EcsMaskBit>(_sortedIncBuffer, inc.Length);
//_excChunckMasks = new ReadOnlySpan<EcsMaskBit>(_sortedExcBuffer, exc.Length);
int _sortedIncBufferLength = inc.Length;
int _sortedExcBufferLength = exc.Length;
if (_sortedIncBufferLength > 1)//перенести этот чек в начала сортировки, для _incChunckMasks.Length == 1 сортировка не нужна
{
for (int i = 0, ii = 0; ii < incChunckMasks.Length; ii++)
{
EcsMaskBit bas = _sortedIncBuffer[i];
int chankIndexX = bas.chankIndex;
int maskX = bas.mask;
for (int j = i + 1; j < _sortedIncBufferLength; j++)
{
if (_sortedIncBuffer[j].chankIndex == chankIndexX)
{
maskX |= _sortedIncBuffer[j].mask;
}
}
incChunckMasks[ii] = new EcsMaskBit(chankIndexX, maskX);
while (++i < _sortedIncBufferLength && _sortedIncBuffer[i].chankIndex == chankIndexX)
{
}
}
}
if (_sortedExcBufferLength > 1)//перенести этот чек в начала сортировки, для _excChunckMasks.Length == 1 сортировка не нужна
{
for (int i = 0, ii = 0; ii < excChunckMasks.Length; ii++)
{
EcsMaskBit bas = _sortedExcBuffer[i];
int chankIndexX = bas.chankIndex;
int maskX = bas.mask;
for (int j = i + 1; j < _sortedExcBufferLength; j++)
{
if (_sortedExcBuffer[j].chankIndex == chankIndexX)
{
maskX |= _sortedExcBuffer[j].mask;
}
}
excChunckMasks[ii] = new EcsMaskBit(chankIndexX, maskX);
while (++i < _sortedExcBufferLength && _sortedExcBuffer[i].chankIndex == chankIndexX)
{
}
}
}
_incChunckMasks = incChunckMasks;
_excChunckMasks = excChunckMasks;
#endif
#endregion
#endregion
#region MyRegion
//_inc = mask.inc;
//_exc = mask.exc;
//int[] inc = mask.inc;
//int[] exc = mask.exc;
//int[] counts = mask.World._poolComponentCounts;
//if (_inc.Length > 1)
//{
// for (int i = 0; i < inc.Length; i++)
// {
// if (counts[inc[i]] <= 0)
// {
// _span = ReadOnlySpan<int>.Empty.GetEnumerator();
// goto skip1;
// }
// for (int j = 0; j < inc.Length - i - 1; j++)
// {
// if (counts[inc[i]] > counts[inc[j]])
// {
// int tmp = inc[j];
// inc[j] = inc[i];
// inc[i] = tmp;
// }
// }
// }
//}
//skip1:;
//if(exc.Length > 1)
//{
// for (int i = 0; i < exc.Length; i++)
// {
// if (counts[exc[i]] <= 0)
// {
// _exc = ReadOnlySpan<int>.Empty;
// goto skip2;
// }
// for (int j = 0; j < exc.Length - i - 1; j++)
// {
// if (counts[exc[i]] < counts[exc[j]])
// {
// int tmp = exc[j];
// exc[j] = exc[i];
// exc[i] = tmp;
// }
// }
// }
//}
//skip2:;
#endregion
} }
public int Current public int Current
{ {
@ -435,21 +738,49 @@ namespace DCFApixels.DragonECS
while (_span.MoveNext()) while (_span.MoveNext())
{ {
int e = _span.Current; int e = _span.Current;
EcsMaskBit bit;
for (int i = 0, iMax = _incChunckMasks.Length; i < iMax; i++) foreach (var bit in _incChunckMasks)
{ {
bit = _incChunckMasks[i];
if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) != bit.mask) if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) != bit.mask)
goto skip; goto skip;
} }
for (int i = 0, iMax = _excChunckMasks.Length; i < iMax; i++) foreach (var bit in _excChunckMasks)
{ {
bit = _excChunckMasks[i];
if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) > 0) if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) > 0)
goto skip; goto skip;
} }
//for (int i = 0, iMax = _incChunckMasks.Length; i < iMax; i++)
//{
// var bit = _incChunckMasks[i];
// if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) != bit.mask)
// goto skip;
//}
//for (int i = 0, iMax = _excChunckMasks.Length; i < iMax; i++)
//{
// var bit = _excChunckMasks[i];
// if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) > 0)
// goto skip;
//}
return true; return true;
skip: continue; skip: continue;
#region MyRegion
//for (int i = 0, iMax = _inc.Length; i < iMax; i++)
//{
// bit = EcsMaskBit.FromID(_inc[i]);
// if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) != bit.mask)
// goto skip;
//}
//for (int i = 0, iMax = _exc.Length; i < iMax; i++)
//{
// bit = EcsMaskBit.FromID(_exc[i]);
// if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) > 0)
// goto skip;
//}
//return true;
//skip: continue;
#endregion
} }
return false; return false;
} }

View File

@ -66,7 +66,9 @@ namespace DCFApixels.DragonECS
_entityDispenser = new IntDispenser(0); _entityDispenser = new IntDispenser(0);
_pools = new IEcsPoolImplementation[POOLS_CAPACITY]; _pools = new IEcsPoolImplementation[POOLS_CAPACITY];
//_poolComponentCounts = new int[POOLS_CAPACITY]; _poolComponentCounts = new int[POOLS_CAPACITY];
//_sortedPoolIds = new int[POOLS_CAPACITY];
//_sortedPoolIdsMapping = new int[POOLS_CAPACITY];
ArrayUtility.Fill(_pools, _nullPool); ArrayUtility.Fill(_pools, _nullPool);
_gens = new short[_entitesCapacity]; _gens = new short[_entitesCapacity];
@ -74,7 +76,6 @@ namespace DCFApixels.DragonECS
ArrayUtility.Fill(_gens, DEATH_GEN_BIT); ArrayUtility.Fill(_gens, DEATH_GEN_BIT);
_delEntBufferCount = 0; _delEntBufferCount = 0;
//_delEntBuffer = new int[_entitesCapacity >> DEL_ENT_BUFFER_SIZE_OFFSET];
_delEntBuffer = new int[_entitesCapacity]; _delEntBuffer = new int[_entitesCapacity];
_entitiesComponentMasks = new int[_entitesCapacity][]; _entitiesComponentMasks = new int[_entitesCapacity][];
for (int i = 0; i < _entitesCapacity; i++) for (int i = 0; i < _entitesCapacity; i++)

View File

@ -12,7 +12,9 @@ namespace DCFApixels.DragonECS
private SparseArray<int> _componentIds = new SparseArray<int>(); private SparseArray<int> _componentIds = new SparseArray<int>();
private int _poolsCount; private int _poolsCount;
internal IEcsPoolImplementation[] _pools; internal IEcsPoolImplementation[] _pools;
//internal int[] _poolComponentCounts; //private int[] _sortedPoolIds;
//private int[] _sortedPoolIdsMapping;
internal int[] _poolComponentCounts;
private static EcsNullPool _nullPool = EcsNullPool.instance; private static EcsNullPool _nullPool = EcsNullPool.instance;
@ -26,6 +28,13 @@ namespace DCFApixels.DragonECS
#region Getters #region Getters
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TPool TestGetPool<TPool>() where TPool : IEcsPoolImplementation, new()
{
return Get<PoolCache<TPool>>().instance;
}
#if UNITY_2020_3_OR_NEWER #if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.Preserve] [UnityEngine.Scripting.Preserve]
#endif #endif
@ -94,7 +103,9 @@ namespace DCFApixels.DragonECS
{ {
int oldCapacity = _pools.Length; int oldCapacity = _pools.Length;
Array.Resize(ref _pools, _pools.Length << 1); Array.Resize(ref _pools, _pools.Length << 1);
//Array.Resize(ref _poolComponentCounts, _pools.Length); Array.Resize(ref _poolComponentCounts, _pools.Length);
//Array.Resize(ref _sortedPoolIds, _pools.Length);
//Array.Resize(ref _sortedPoolIdsMapping, _pools.Length);
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length); ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
for (int i = 0; i < _entitesCapacity; i++) for (int i = 0; i < _entitesCapacity; i++)
@ -111,18 +122,19 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region Pools mediation #region Pools mediation
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void RegisterEntityComponent(int entityID, int componentTypeID, EcsMaskBit maskBit) private void RegisterEntityComponent(int entityID, int componentTypeID, EcsMaskBit maskBit)
{ {
//_poolComponentCounts[componentTypeID]++; _poolComponentCounts[componentTypeID]++;
_componentCounts[entityID]++; _componentCounts[entityID]++;
_entitiesComponentMasks[entityID][maskBit.chankIndex] |= maskBit.mask; _entitiesComponentMasks[entityID][maskBit.chankIndex] |= maskBit.mask;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UnregisterEntityComponent(int entityID, int componentTypeID, EcsMaskBit maskBit) private void UnregisterEntityComponent(int entityID, int componentTypeID, EcsMaskBit maskBit)
{ {
//_poolComponentCounts[componentTypeID]--; _poolComponentCounts[componentTypeID]--;
var count = --_componentCounts[entityID]; var count = --_componentCounts[entityID];
_entitiesComponentMasks[entityID][maskBit.chankIndex] &= ~maskBit.mask; _entitiesComponentMasks[entityID][maskBit.chankIndex] &= ~maskBit.mask;