Search Unity

Best practice for storing fixed-length arrays on entities

Discussion in 'Entity Component System' started by MarkFaasen, Jun 5, 2021.

  1. MarkFaasen

    MarkFaasen

    Joined:
    Oct 23, 2018
    Posts:
    13
    Hello everyone,

    I'm looking to improve my understanding of NativeArrays and DynamicBuffers in ECS Context.
    Say, I want to have a large array (say 1million ints) to be used in System and Jobs. My current approach would be to give an singleton entity a IBufferElementData component and then use buffer.EnsureCapacity(1000000) and buffer.Length = 1000000 so it wont expand. That seems kinda "wrong" because I know the length beforehand and know that it wont change size. I tried the tag [InternalBufferCapacity(1000000)] but then I get errors about an component being too large (I probably make a mistake somewhere).
    Are there any benefits to using a standard array of fixed length inside a standard component (memory layout / lookups / access in job)?
    This question is intended to shed some light on behind the scenes stuff. Like how and where is a DynamicBuffer/Big Component stored, what about chucks, cpu cache and job access.
    Thanks for reading!
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    This is most likely, that system tries put 1 mln capacity in a chunk. Which too large. Try set size to one, and resize at initialisation. Then your buffer will be store on the heap, not in the chunk, if is too large. Also you can resize it when needed. And remember, there also NativeList for you to use.
     
  3. MarkFaasen

    MarkFaasen

    Joined:
    Oct 23, 2018
    Posts:
    13
    Ah yes that makes sense, thanks Antypodish. What I don't understand now is the difference between InternalBufferCapacity(1) and not setting this tag at all. I made an example with 5000 entities and each has a IBufferElementData containing a struct.
    -When I set the InternalBufferCapacity to high (e.g. 1000), I get an error complaining about the Archetype not being able to fit in a chunk of 16kb, understandable.
    -When I remove the Attribute and add 1000 items during entity creation I can fit 48 Entities in a chunk.
    -When I set InternalBufferCapacity(1) and then also add 1000 items during entity creation I can fit 66 Entities in a chunk.
    -When I set InternalBufferCapacity(3) and then also add 1000 items during entity creation I can fit 56 Entities in a chunk.
    -When I set InternalBufferCapacity(5) and then also add 1000 items during entity creation I can fit 43 Entities in a chunk.
    What is happening here? What goes in heap, what stays in the chunk?
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    What is happening, when you set InternalBufferCapacity(1), chunk is created with entities, and one element capacity on the buffer.
    But now you add 1000 elements, meaning you resize the buffer.
    When you resize buffer up, the buffer is moved outside the chunk and stored on the heap.
    The space in the chunk stays reserved, as per InternalBufferCapacity.
    But then, it is simply not used. Instead heap is used.

    The consequence is, that accessing Dynamic Buffer is a bit slower, when outside of the chunk, loosing the advantage of data being store in the chunk.
     
  5. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    When you want the data to reside outside the chunk use internal buffer capacity 0
     
  6. MarkFaasen

    MarkFaasen

    Joined:
    Oct 23, 2018
    Posts:
    13
    Thanks to both of you for your insights. It has helped me to get a better understanding of the topic.