-
-
Notifications
You must be signed in to change notification settings - Fork 92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Speedup TryGet #232
base: master
Are you sure you want to change the base?
Speedup TryGet #232
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using Arch.Core; | ||
using Arch.Core.Utils; | ||
|
||
namespace Arch.Benchmarks; | ||
|
||
[HtmlExporter] | ||
[MemoryDiagnoser] | ||
[HardwareCounters(HardwareCounter.CacheMisses)] | ||
public class TryGetBenchmark | ||
{ | ||
private static World _world; | ||
private static List<Entity> _entities; | ||
|
||
private Consumer _consumer = new(); | ||
|
||
[GlobalSetup] | ||
public void Setup() | ||
{ | ||
_world = World.Create(); | ||
|
||
_entities = new List<Entity>(1_000_000); | ||
for (var index = 0; index < 1_000_000; index++) | ||
{ | ||
_entities.Add(_world.Create(new Transform(), new Velocity())); | ||
} | ||
} | ||
|
||
[Benchmark] | ||
public void TryGetGenericRef() | ||
{ | ||
for (var index = 0; index < _entities.Count; index++) | ||
{ | ||
var entity = _entities[index]; | ||
var xform = _world.TryGetRef<Transform>(entity, out var exists); | ||
|
||
if (exists) | ||
{ | ||
_consumer.Consume(xform); | ||
} | ||
} | ||
} | ||
|
||
[Benchmark] | ||
public void TryGetGeneric() | ||
{ | ||
for (var index = 0; index < _entities.Count; index++) | ||
{ | ||
var entity = _entities[index]; | ||
|
||
if (_world.TryGet<Transform>(entity, out var xform)) | ||
{ | ||
_consumer.Consume(xform); | ||
} | ||
} | ||
} | ||
|
||
[Benchmark] | ||
public void TryGet() | ||
{ | ||
for (var index = 0; index < _entities.Count; index++) | ||
{ | ||
var entity = _entities[index]; | ||
|
||
if (_world.TryGet(entity, Component.GetComponentType(typeof(Transform)), out var xform)) | ||
{ | ||
_consumer.Consume(xform); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
using Arch.Core.Extensions.Internal; | ||
using Arch.Core.Utils; | ||
using Collections.Pooled; | ||
using CommunityToolkit.HighPerformance; | ||
using Schedulers; | ||
using Component = Arch.Core.Utils.Component; | ||
|
||
|
@@ -983,18 +984,18 @@ public ref T Get<T>(Entity entity) | |
[Pure] | ||
public bool TryGet<T>(Entity entity, out T? component) | ||
{ | ||
component = default; | ||
|
||
var entitySlot = EntityInfo.GetEntitySlot(entity.Id); | ||
var slot = entitySlot.Slot; | ||
var archetype = entitySlot.Archetype; | ||
ref var slot = ref EntityInfo.EntitySlots[entity.Id]; | ||
|
||
if (!archetype.Has<T>()) | ||
if (!slot.Archetype.TryIndex<T>(out int compIndex)) | ||
{ | ||
component = default; | ||
return false; | ||
} | ||
|
||
component = archetype.Get<T>(ref slot); | ||
ref var chunk = ref slot.Archetype.GetChunk(slot.Slot.ChunkIndex); | ||
Debug.Assert(compIndex != -1 && compIndex < chunk.Components.Length, $"Index is out of bounds, component {typeof(T)} with id {compIndex} does not exist in this chunk."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The assert message was also pilfered from elsewhere, and the "does not exist in this chunk" should probably be updated as it is not in |
||
var array = Unsafe.As<T[]>(chunk.Components.DangerousGetReferenceAt(compIndex)); | ||
component = array[slot.Slot.Index]; | ||
return true; | ||
} | ||
|
||
|
@@ -1009,16 +1010,14 @@ public bool TryGet<T>(Entity entity, out T? component) | |
[Pure] | ||
public ref T TryGetRef<T>(Entity entity, out bool exists) | ||
{ | ||
var entitySlot = EntityInfo.GetEntitySlot(entity.Id); | ||
var slot = entitySlot.Slot; | ||
var archetype = entitySlot.Archetype; | ||
Comment on lines
-1012
to
-1014
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIRC these changes were from an older arch version and aren't really required anymore. I.e., previously it was getting the entity slot twice using var slot = EntityInfo.GetSlot(entity.Id);
var archetype = EntityInfo.GetArchetype(entity.Id); but the current version doesn't seem to do that anymore. |
||
ref var slot = ref EntityInfo.EntitySlots[entity.Id]; | ||
|
||
if (!(exists = archetype.Has<T>())) | ||
if (!(exists = slot.Archetype.Has<T>())) | ||
{ | ||
return ref Unsafe.NullRef<T>(); | ||
} | ||
|
||
return ref archetype.Get<T>(ref slot); | ||
Comment on lines
-1016
to
-1021
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can probably also be changed to use TryGetIndex instead of |
||
return ref slot.Archetype.Get<T>(ref slot.Slot); | ||
} | ||
|
||
/// <summary> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The assert text should probably be updated and I don't think its actually correct, I'm not sure if -1 is even possible? I think I initially just pilfered part of the asset from
Chunk.Index<T>()
and never really updated the text.