Add archetype iteration and has component benchmarks (#3607)

This commit is contained in:
DrSmugleaf
2022-12-22 23:31:05 +01:00
committed by GitHub
parent 272c3f8e84
commit e5dde1c7ad

View File

@@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using JetBrains.Annotations;
using Robust.Shared.Analyzers;
namespace Robust.Benchmarks.EntityManager;
@@ -11,9 +14,11 @@ namespace Robust.Benchmarks.EntityManager;
public class ArchetypeComponentAccessBenchmark
{
private const int N = 10000;
private const int Entity = 1584;
private Dictionary<Type, Dictionary<int, object>> _componentDictionary = default!;
private Archetype<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10> _archetype = default!;
private Consumer _consumer = default!;
[GlobalSetup]
public void GlobalSetup()
@@ -58,54 +63,56 @@ public class ArchetypeComponentAccessBenchmark
_archetype.AddComponent(i, new Type9());
_archetype.AddComponent(i, new Type10());
}
_consumer = new Consumer();
}
[Benchmark]
public Type1 GetSingleComponentsDictionary()
public Type1 GetSingleComponentDictionary()
{
return (Type1) _componentDictionary[typeof(Type1)][1584];
return (Type1) _componentDictionary[typeof(Type1)][Entity];
}
[Benchmark]
public Type1 GetSingleComponentsArchetypeCast()
public Type1 GetSingleComponentArchetypeCast()
{
return _archetype.GetComponentCast<Type1>(1584);
return _archetype.GetComponentCast<Type1>(Entity);
}
[Benchmark]
public Type1 GetSingleComponentsArchetypeCastHandle()
public Type1 GetSingleComponentArchetypeCastHandle()
{
// Handle is the same as the id
return _archetype.GetComponentCastHandle<Type1>(1584);
return _archetype.GetComponentCastHandle<Type1>(Entity);
}
[Benchmark]
public Type1 GetSingleComponentsArchetypeUnsafe()
public Type1 GetSingleComponentArchetypeUnsafe()
{
return _archetype.GetComponentUnsafe<Type1>(1584);
return _archetype.GetComponentUnsafe<Type1>(Entity);
}
[Benchmark]
public Type1 GetSingleComponentsArchetypeUnsafeHandle()
public Type1 GetSingleComponentArchetypeUnsafeHandle()
{
// Handle is the same as the id
return _archetype.GetComponentUnsafeHandle<Type1>(1584);
return _archetype.GetComponentUnsafeHandle<Type1>(Entity);
}
[Benchmark]
public (Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10) GetTenComponentsDictionary()
{
return (
(Type1) _componentDictionary[typeof(Type1)][1584],
(Type2) _componentDictionary[typeof(Type2)][1584],
(Type3) _componentDictionary[typeof(Type3)][1584],
(Type4) _componentDictionary[typeof(Type4)][1584],
(Type5) _componentDictionary[typeof(Type5)][1584],
(Type6) _componentDictionary[typeof(Type6)][1584],
(Type7) _componentDictionary[typeof(Type7)][1584],
(Type8) _componentDictionary[typeof(Type8)][1584],
(Type9) _componentDictionary[typeof(Type9)][1584],
(Type10) _componentDictionary[typeof(Type10)][1584]
(Type1) _componentDictionary[typeof(Type1)][Entity],
(Type2) _componentDictionary[typeof(Type2)][Entity],
(Type3) _componentDictionary[typeof(Type3)][Entity],
(Type4) _componentDictionary[typeof(Type4)][Entity],
(Type5) _componentDictionary[typeof(Type5)][Entity],
(Type6) _componentDictionary[typeof(Type6)][Entity],
(Type7) _componentDictionary[typeof(Type7)][Entity],
(Type8) _componentDictionary[typeof(Type8)][Entity],
(Type9) _componentDictionary[typeof(Type9)][Entity],
(Type10) _componentDictionary[typeof(Type10)][Entity]
);
}
@@ -113,16 +120,16 @@ public class ArchetypeComponentAccessBenchmark
public (Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10) GetTenComponentsArchetypeCast()
{
return (
_archetype.GetComponentCast<Type1>(1584),
_archetype.GetComponentCast<Type2>(1584),
_archetype.GetComponentCast<Type3>(1584),
_archetype.GetComponentCast<Type4>(1584),
_archetype.GetComponentCast<Type5>(1584),
_archetype.GetComponentCast<Type6>(1584),
_archetype.GetComponentCast<Type7>(1584),
_archetype.GetComponentCast<Type8>(1584),
_archetype.GetComponentCast<Type9>(1584),
_archetype.GetComponentCast<Type10>(1584)
_archetype.GetComponentCast<Type1>(Entity),
_archetype.GetComponentCast<Type2>(Entity),
_archetype.GetComponentCast<Type3>(Entity),
_archetype.GetComponentCast<Type4>(Entity),
_archetype.GetComponentCast<Type5>(Entity),
_archetype.GetComponentCast<Type6>(Entity),
_archetype.GetComponentCast<Type7>(Entity),
_archetype.GetComponentCast<Type8>(Entity),
_archetype.GetComponentCast<Type9>(Entity),
_archetype.GetComponentCast<Type10>(Entity)
);
}
@@ -131,16 +138,16 @@ public class ArchetypeComponentAccessBenchmark
{
// Handle is the same as the id
return (
_archetype.GetComponentCastHandle<Type1>(1584),
_archetype.GetComponentCastHandle<Type2>(1584),
_archetype.GetComponentCastHandle<Type3>(1584),
_archetype.GetComponentCastHandle<Type4>(1584),
_archetype.GetComponentCastHandle<Type5>(1584),
_archetype.GetComponentCastHandle<Type6>(1584),
_archetype.GetComponentCastHandle<Type7>(1584),
_archetype.GetComponentCastHandle<Type8>(1584),
_archetype.GetComponentCastHandle<Type9>(1584),
_archetype.GetComponentCastHandle<Type10>(1584)
_archetype.GetComponentCastHandle<Type1>(Entity),
_archetype.GetComponentCastHandle<Type2>(Entity),
_archetype.GetComponentCastHandle<Type3>(Entity),
_archetype.GetComponentCastHandle<Type4>(Entity),
_archetype.GetComponentCastHandle<Type5>(Entity),
_archetype.GetComponentCastHandle<Type6>(Entity),
_archetype.GetComponentCastHandle<Type7>(Entity),
_archetype.GetComponentCastHandle<Type8>(Entity),
_archetype.GetComponentCastHandle<Type9>(Entity),
_archetype.GetComponentCastHandle<Type10>(Entity)
);
}
@@ -148,16 +155,16 @@ public class ArchetypeComponentAccessBenchmark
public (Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10) GetTenComponentsArchetypeUnsafe()
{
return (
_archetype.GetComponentUnsafe<Type1>(1584),
_archetype.GetComponentUnsafe<Type2>(1584),
_archetype.GetComponentUnsafe<Type3>(1584),
_archetype.GetComponentUnsafe<Type4>(1584),
_archetype.GetComponentUnsafe<Type5>(1584),
_archetype.GetComponentUnsafe<Type6>(1584),
_archetype.GetComponentUnsafe<Type7>(1584),
_archetype.GetComponentUnsafe<Type8>(1584),
_archetype.GetComponentUnsafe<Type9>(1584),
_archetype.GetComponentUnsafe<Type10>(1584)
_archetype.GetComponentUnsafe<Type1>(Entity),
_archetype.GetComponentUnsafe<Type2>(Entity),
_archetype.GetComponentUnsafe<Type3>(Entity),
_archetype.GetComponentUnsafe<Type4>(Entity),
_archetype.GetComponentUnsafe<Type5>(Entity),
_archetype.GetComponentUnsafe<Type6>(Entity),
_archetype.GetComponentUnsafe<Type7>(Entity),
_archetype.GetComponentUnsafe<Type8>(Entity),
_archetype.GetComponentUnsafe<Type9>(Entity),
_archetype.GetComponentUnsafe<Type10>(Entity)
);
}
@@ -166,20 +173,125 @@ public class ArchetypeComponentAccessBenchmark
{
// Handle is the same as the id
return (
_archetype.GetComponentUnsafeHandle<Type1>(1584),
_archetype.GetComponentUnsafeHandle<Type2>(1584),
_archetype.GetComponentUnsafeHandle<Type3>(1584),
_archetype.GetComponentUnsafeHandle<Type4>(1584),
_archetype.GetComponentUnsafeHandle<Type5>(1584),
_archetype.GetComponentUnsafeHandle<Type6>(1584),
_archetype.GetComponentUnsafeHandle<Type7>(1584),
_archetype.GetComponentUnsafeHandle<Type8>(1584),
_archetype.GetComponentUnsafeHandle<Type9>(1584),
_archetype.GetComponentUnsafeHandle<Type10>(1584)
_archetype.GetComponentUnsafeHandle<Type1>(Entity),
_archetype.GetComponentUnsafeHandle<Type2>(Entity),
_archetype.GetComponentUnsafeHandle<Type3>(Entity),
_archetype.GetComponentUnsafeHandle<Type4>(Entity),
_archetype.GetComponentUnsafeHandle<Type5>(Entity),
_archetype.GetComponentUnsafeHandle<Type6>(Entity),
_archetype.GetComponentUnsafeHandle<Type7>(Entity),
_archetype.GetComponentUnsafeHandle<Type8>(Entity),
_archetype.GetComponentUnsafeHandle<Type9>(Entity),
_archetype.GetComponentUnsafeHandle<Type10>(Entity)
);
}
// Just a bunch of types to pad the size of the arrays and such.
[Benchmark]
public bool HasSingleComponentDictionary()
{
return _componentDictionary[typeof(Type1)].ContainsKey(Entity);
}
[Benchmark]
public bool HasSingleComponentArchetype()
{
return _archetype.HasComponent<Type1>();
}
[Benchmark]
public bool HasTenComponentsDictionary()
{
return _componentDictionary[typeof(Type1)].ContainsKey(Entity) &&
_componentDictionary[typeof(Type2)].ContainsKey(Entity) &&
_componentDictionary[typeof(Type3)].ContainsKey(Entity) &&
_componentDictionary[typeof(Type4)].ContainsKey(Entity) &&
_componentDictionary[typeof(Type5)].ContainsKey(Entity) &&
_componentDictionary[typeof(Type6)].ContainsKey(Entity) &&
_componentDictionary[typeof(Type7)].ContainsKey(Entity) &&
_componentDictionary[typeof(Type8)].ContainsKey(Entity) &&
_componentDictionary[typeof(Type9)].ContainsKey(Entity) &&
_componentDictionary[typeof(Type10)].ContainsKey(Entity);
}
[Benchmark]
public bool HasTenComponentsArchetype()
{
return _archetype.HasComponent<Type1>() &&
_archetype.HasComponent<Type2>() &&
_archetype.HasComponent<Type3>() &&
_archetype.HasComponent<Type4>() &&
_archetype.HasComponent<Type5>() &&
_archetype.HasComponent<Type6>() &&
_archetype.HasComponent<Type7>() &&
_archetype.HasComponent<Type8>() &&
_archetype.HasComponent<Type9>() &&
_archetype.HasComponent<Type10>();
}
[Benchmark]
public void IterateSingleComponentDictionary()
{
foreach (Type1 value in _componentDictionary[typeof(Type1)].Values)
{
_consumer.Consume(value);
}
}
[Benchmark]
public void IterateCastSingleComponentArchetype()
{
foreach (var value in _archetype.IterateSingleCast<Type1>())
{
_consumer.Consume(value);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void IteratorSingle(Type1 t1)
{
}
[Benchmark]
public void IterateDelegateSingleComponentArchetype()
{
_archetype.IterateSingleDelegate<Type1>(static t1 => IteratorSingle(t1));
}
[Benchmark]
public void IterateTenComponentsDictionary()
{
for (var i = 0; i < N; i++)
{
_consumer.Consume((
(Type1) _componentDictionary[typeof(Type1)][i],
(Type2) _componentDictionary[typeof(Type2)][i],
(Type3) _componentDictionary[typeof(Type3)][i],
(Type4) _componentDictionary[typeof(Type4)][i],
(Type5) _componentDictionary[typeof(Type5)][i],
(Type6) _componentDictionary[typeof(Type6)][i],
(Type7) _componentDictionary[typeof(Type7)][i],
(Type8) _componentDictionary[typeof(Type8)][i],
(Type9) _componentDictionary[typeof(Type9)][i],
(Type10) _componentDictionary[typeof(Type10)][i]
));
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void IteratorTen(ref Type1 t1, ref Type2 t2, ref Type3 t3, ref Type4 t4, ref Type5 t5, ref Type6 t6,
ref Type7 t7, ref Type8 t8, ref Type9 t9, ref Type10 t10)
{
}
[Benchmark]
public void IterateDelegateTenComponentsArchetype()
{
_archetype.IterateDelegate(
static (ref Type1 t1, ref Type2 t2, ref Type3 t3, ref Type4 t4, ref Type5 t5, ref Type6 t6, ref Type7 t7,
ref Type8 t8, ref Type9 t9, ref Type10 t10) =>
IteratorTen(ref t1, ref t2, ref t3, ref t4, ref t5, ref t6, ref t7, ref t8, ref t9, ref t10)
);
}
// @formatter:off
// ReSharper disable UnusedType.Local
@@ -271,8 +383,9 @@ public class ArchetypeComponentAccessBenchmark
}
}
public T GetComponentCast<T>(int entity, T val = default) where T : struct
public T GetComponentCast<T>(int entity) where T : struct
{
Unsafe.SkipInit(out T val);
var id = _ids[entity];
return val switch
@@ -291,8 +404,9 @@ public class ArchetypeComponentAccessBenchmark
};
}
public T GetComponentCastHandle<T>(int handle, T val = default) where T : struct
public T GetComponentCastHandle<T>(int handle) where T : struct
{
Unsafe.SkipInit(out T val);
return val switch
{
T1 => (T) (object) _t1Comps[handle]!,
@@ -309,8 +423,9 @@ public class ArchetypeComponentAccessBenchmark
};
}
public ref T GetComponentUnsafe<T>(int entity, T val = default) where T : struct
public ref T GetComponentUnsafe<T>(int entity) where T : struct
{
Unsafe.SkipInit(out T val);
var id = _ids[entity];
switch (val)
@@ -340,33 +455,153 @@ public class ArchetypeComponentAccessBenchmark
}
}
public ref T GetComponentUnsafeHandle<T>(int handle, T val = default) where T : struct
public T GetComponentUnsafeHandle<T>(int handle) where T : struct
{
Unsafe.SkipInit(out T val);
switch (val)
{
case T1:
return ref Unsafe.As<T1, T>(ref _t1Comps[handle]);
return Unsafe.As<T1, T>(ref _t1Comps[handle]);
case T2:
return ref Unsafe.As<T2, T>(ref _t2Comps[handle]);
return Unsafe.As<T2, T>(ref _t2Comps[handle]);
case T3:
return ref Unsafe.As<T3, T>(ref _t3Comps[handle]);
return Unsafe.As<T3, T>(ref _t3Comps[handle]);
case T4:
return ref Unsafe.As<T4, T>(ref _t4Comps[handle]);
return Unsafe.As<T4, T>(ref _t4Comps[handle]);
case T5:
return ref Unsafe.As<T5, T>(ref _t5Comps[handle]);
return Unsafe.As<T5, T>(ref _t5Comps[handle]);
case T6:
return ref Unsafe.As<T6, T>(ref _t6Comps[handle]);
return Unsafe.As<T6, T>(ref _t6Comps[handle]);
case T7:
return ref Unsafe.As<T7, T>(ref _t7Comps[handle]);
return Unsafe.As<T7, T>(ref _t7Comps[handle]);
case T8:
return ref Unsafe.As<T8, T>(ref _t8Comps[handle]);
return Unsafe.As<T8, T>(ref _t8Comps[handle]);
case T9:
return ref Unsafe.As<T9, T>(ref _t9Comps[handle]);
return Unsafe.As<T9, T>(ref _t9Comps[handle]);
case T10:
return ref Unsafe.As<T10, T>(ref _t10Comps[handle]);
return Unsafe.As<T10, T>(ref _t10Comps[handle]);
default:
throw new ArgumentException($"Unknown type: {typeof(T)}");
}
}
public bool HasComponent<T>()
{
Unsafe.SkipInit(out T val);
return val switch
{
T1 => true,
T2 => true,
T3 => true,
T4 => true,
T5 => true,
T6 => true,
T7 => true,
T8 => true,
T9 => true,
T10 => true,
_ => false,
};
}
public IEnumerable<T> IterateSingleCast<T>()
{
Unsafe.SkipInit(out T val);
return val switch
{
T1 => _t1Comps.Cast<T>(),
T2 => _t2Comps.Cast<T>(),
T3 => _t3Comps.Cast<T>(),
T4 => _t4Comps.Cast<T>(),
T5 => _t5Comps.Cast<T>(),
T6 => _t6Comps.Cast<T>(),
T7 => _t7Comps.Cast<T>(),
T8 => _t8Comps.Cast<T>(),
T9 => _t9Comps.Cast<T>(),
T10 => _t10Comps.Cast<T>(),
_ => throw new ArgumentException($"Unknown type: {typeof(T)}")
};
}
private void IterateSingleSpan<T, TComp>([RequireStaticDelegate] Action<T> action, TComp[] array) where T : struct
{
foreach (ref var comp in array.AsSpan())
{
action(Unsafe.As<TComp, T>(ref comp));
}
}
public void IterateSingleDelegate<T>([RequireStaticDelegate] Action<T> action) where T : struct
{
Unsafe.SkipInit(out T val);
switch (val)
{
case T1:
IterateSingleSpan(action, _t1Comps);
break;
case T2:
IterateSingleSpan(action, _t2Comps);
break;
case T3:
IterateSingleSpan(action, _t3Comps);
break;
case T4:
IterateSingleSpan(action, _t4Comps);
break;
case T5:
IterateSingleSpan(action, _t5Comps);
break;
case T6:
IterateSingleSpan(action, _t6Comps);
break;
case T7:
IterateSingleSpan(action, _t7Comps);
break;
case T8:
IterateSingleSpan(action, _t8Comps);
break;
case T9:
IterateSingleSpan(action, _t9Comps);
break;
case T10:
IterateSingleSpan(action, _t10Comps);
break;
default:
throw new ArgumentException($"Unknown type: {typeof(T)}");
}
}
public delegate void Iterator(ref T1 t1, ref T2 t2, ref T3 t3, ref T4 t4, ref T5 t5, ref T6 t6, ref T7 t7,
ref T8 t8, ref T9 t9, ref T10 t10);
public void IterateDelegate([RequireStaticDelegate] Iterator action)
{
var t1Span = _t1Comps.AsSpan();
var t2Span = _t2Comps.AsSpan();
var t3Span = _t3Comps.AsSpan();
var t4Span = _t4Comps.AsSpan();
var t5Span = _t5Comps.AsSpan();
var t6Span = _t6Comps.AsSpan();
var t7Span = _t7Comps.AsSpan();
var t8Span = _t8Comps.AsSpan();
var t9Span = _t9Comps.AsSpan();
var t10Span = _t10Comps.AsSpan();
for (var i = 0; i < _ids.Count; i++)
{
action(
ref t1Span[i],
ref t2Span[i],
ref t3Span[i],
ref t4Span[i],
ref t5Span[i],
ref t6Span[i],
ref t7Span[i],
ref t8Span[i],
ref t9Span[i],
ref t10Span[i]
);
}
}
}
}