Good practice around Components quantity and size

Hello,

I think no one asked this before (since I found nothing directly related to these questions on the forum), so here are my questions:

  • Is there any downside or limit on the number of components on the same entity ?
  • Is there a limit on the size of a component ? (I’ve seen people talking about the size needed to be under 100 bytes)

Thanks!

PS: I’m only talking about IComponentData and not regular Unity components obviously

ECS Memory Layout read this topic, it can help you understand ecs memory layout and how adding more components affect performance

1 Like

Chunks are currently 16 kilobytes, so the larger your entity is the fewer that fit in a chunk. That would put a hard cap of 16 kilobytes on the size of an entity. DynamicBuffer can alleviate that pressure with a basically unlimited size cap (gigabytes if you are a crazy person).

IJobForEach dispatches across cores per-chunk, so in some scenarios you actually want fewer entities in a chunk. In general though, fit as many as you can in a single chunk for the best performance.

1 Like

Just making sure I understand this correctly:

If I have these entities:

Would that result in:

I’m guessing it’s not result B because then every single entity that has at least a Translation component would end up in the same chunk?

Yes, it will be option A.

*Edit: Wrong answer.

[ ]'s

Actually, as today, it’s less than 16kb with 256b reserved as a header.
They have stated that, in the future, the chunk size could be configurable.
https://discussions.unity.com/t/702049/18

[ ]'s

So if this is happening:

How does an IJobChunk launched with an EntityQuery{ All = Translation, Rotation } decide whether to choose Chunk1 or Chunk2? We can check for optional components in IJobChunks, so does that mean it’ll iterate both on Chunk1 and Chunk2?

And if it iterates on both, how does it avoid modifying the same data twice?

Sorry, I just misread.
Entities are not shared between chunks. In your case each entity will be in a different chunk.

[ ]'s

2 Likes

In an IJobChunk, you only get the necessary components you need for that particular job, not the whole entity with all of its components, because you specify the ArchetypeChunkComponentType. I imagine IJobForEach would be similar.

So if you have entities with 100 components, each with a single float3 in them, and a job that requires 5 of these components, the resulting chunk will only consist of 5 float3s. In that case, it’s better than to have 5 components with 20 float3’s each.

Edit: Clarification: The resulting chunk will then only consist of a large number of entities because it needs only 5 float3s. Whereas if entities had 5 components with 20 float3s each, then the resulting chunk would have a lower number of entities due to more data being passed in. So the way I understand it is that there are as many chunk types as there are job types.

Right?

1 Like

A chunk contains exactly one archetype. So in this example:

  • EntityA

  • Translation

  • Rotation

  • Scale

  • EntityB

  • Translation

  • Rotation

  • EntityC

  • MyAIController

  • EntityD

  • Translation

  • Rotation

EntityA would exist in ChunkA, which has a header and an array of Translation, Rotation, and Scale components.

EntityB would exist in ChunkB, which has a header and an array of Translation and Rotation components. These arrays are slightly larger than ChunkA.

EntityC would exist in ChunkC, which has a header and an array of MyAIController components.

EntityD would exist in ChunkB, as its archetype exactly matches EntityB.

An IJobForEach<Translation, Rotation> would iterate over both ChunkA and ChunkB, as their archetypes both fulfill the underlying EntityQuery. The Scale array in ChunkA would not be touched.

An IJobChunk could use an EntityQuery for just the Translation component, but have ArchetypeChunkComponentTypes for Rotation and Scale. It can then check whether or not the active chunk has those additional components and do selective logic appropriately. The Transform system does this. Some of my own code does this as well. It is crazy powerful!

3 Likes