Not directly DOTS, but definitely data-oriented!
A couple of days ago I started attempting to try and hide AoS vs SoA implementations. This, all to be able to experiment with it more easily during development (because it's a real pain in the ass to change such code). The idea was very simple: wrap the data accesses in a structure that fetches it from the correct place, and rely on the compiler to optimize the code.
I ran into trouble earlier than expected!
In a first attempt, I have some (non-bursted) code where I changed the return value of a collection: from a pointer, to a struct containing a pointer.
That's the only meaningful difference in the code.. yet, my performance tests show I lose around 5% (and up to 20% if I access neighbouring data in addition to that).
I have added aggressive inlining to all the relevant functions, so I do not understand where this performance difference comes from. Any ideas about what I could've missed? Maybe some ideas to figure out more?
The struct is just this.
public unsafe readonly struct TileDataRef
{
public readonly TestTileData* _tileData;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TileDataRef(TestDataBlock8x8 block, int localFlatIndex)
{
// of course this was done in the containing data structure before, but it's constructed in the same place
_tileData = block.GetDataPtr() + localFlatIndex;
}
public bool IsValid => _tileData != null;
public static implicit operator bool(TileDataRef t) => t._tileData != null;
public ETileType Type
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _tileData->Type;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _tileData->Type = value;
}
// more accessors here ..