Search code examples
c#.netdata-structurescpu-cache

Data structure in .Net keeping heterogeneous structs contiguous in memory


I'm looking for a data structure in .Net which keep heterogeneous structs contiguous in memory in order to be cpu-cache-friendly.

This type of data structure is explained in this blog : T-machine.org at the Iteration 4.

In .Net an array of value types (structs) keeps data contiguous in memory, but this is only working for a no-generic array. I tried to create a ValueType[], but structs are boxed. So the references are contiguous in memory but not the real data.

After many tries I don't think this is possible natively in .Net. The only possible solution I see, it's to manually managed the seralization and deserialization of structs in a byte array, but I don't think it will be performant.

Did you find a native solution? or a better solution that mine?

Edit 1: I'm trying to implement an entity-component-system as described in the T-Machine.org blog.


Solution

  • No. There is no way to do Iteration 4 in C#. You can't decide where in memory a .NET struct or class will be put. There is nothing similar to Placement New of C++.

    But note that even Iteration 4 seems to have more problems than solutions:

    At this point, our iterations are quite good, but we’re seeing some recurring problems:

    • Re-allocation of arrays when Components are added/removed (I’ve not covered this above – if you’re not familiar with the problem, google “C dynamic array”)
    • Fragmentation (affects every iteration after Iteration 1, which doesn’t get any worse simple because it’s already as bad as it could be)
    • Cross-referencing (which I skipped)

    but

    if you have struct of around the same size, the union trick could be enough...

    public enum StructType
    {
        Velocity = 0,
        Position = 1,
        Foo = 2,
        Bar = 3,
    }
    
    public struct Velocity
    {
        public int Vx;
        public int Vy;
    }
    
    public struct Position
    {
        public int X;
        public int Y;
        public int Z;
    }
    
    public struct Foo
    {
        public double Weight;
        public double Height;
        public int Age;
    }
    
    public struct Bar
    {
        public int ColorR;
        public int ColorG;
        public int ColorB;
        public int Transparency;
    }
    
    [StructLayout(LayoutKind.Explicit)]
    public struct SuperStruct
    {
        [FieldOffset(0)]
        public StructType StructType;
    
        [FieldOffset(4)]
        public Velocity Velocity;
    
        [FieldOffset(4)]
        public Position Position;
    
        [FieldOffset(4)]
        public Foo Foo;
    
        [FieldOffset(4)]
        public Bar Bar;
    }
    

    "officially" in C# there are no C unions. But thorugh the use of FixedLayout and FieldOffset you can create them. Note that they are totally incompatible with reference types, and clearly the size of the SuperStruct will be the size of the biggest possible element. In this case, 32 bytes, because Foo is 20 bytes, but there is some padding needed before and after it to align to the 8 bytes boundary.

    Clearly your array would be of SuperStruct types. Note that by following the Iterion 4 example, the StructType isn't strictly necessary, because the types of the elements is written in other places.