Iterating entities based on tag filtering vs flag checking.

From what I understand, ECS is intended to have systems work on entites based on some filter. While I understand theoretically how this leads to a clean and optimal codebase, from my profiling adding and removing components is quite expensive.

It’s much much faster to just iterate over all entities and doing a simple branch on some boolean component.

For example, when I got started with Unity ECS tutorials I went through all suggested to add and remove tag components. For a unit selection system in a game, when the player selects some units, a selected tag is added to them, and any systems required will know what entities to work on.

But its much faster to have a permanent component with a boolean “selected”. This is on 20 thousand + entities.

Thoughts and opinions?

I guess I’m a bit confused by your scenario, if you have a “SelectedSystem” that is querying for “Selected” components then it would literally not run unless those components exist. Presumably selection is not something that happens every frame, so I would think you would actually be saving quite a bit by not iterating 20 thousand entities every single frame for an operation that will probably not be happening that often.

When you profiled this, were you using command buffers to ensure you weren’t forcing multiple sync points during simulation processing? Were you tagging inside bursted parallel jobs? Were you using batch operations where possible?

No the components would always exist, but the component has a flag, rather than the component being a flag itself.

I was using command buffers. Command buffers run on the main thread which I am avoiding like the plague. It was burst compiled. What is a batch operation?

EntityManager.AddComponent<SelectedTag>(aNativeArrayOfEntititesToBeTagged);
1 Like

You can use entity queries instead of an array of entities, and you can pass them to command buffers too.

You can (and should) use command buffers inside jobs. Their playback will of course happen later on in the main thread, but all structural changes happen on the main thread, there’s no avoiding that.

In your OP you said that it’s faster to iterate and check for the flag on your components than to do a structural change - but it seems like you’re not considering the cost of having to do that iteration every single frame. You’re forcing your system to iterate all the relevant entities every frame as opposed to the one-time cost of the structural change whenever selection state changes. To me the latter option sounds like it would save more work overall, but I guess it depends on context.

1 Like

You are right that it saves the iteration cost. But think about this. Lets say on the odd occasion on one frame you end up having alot of structural changes from many different systems all played back in commandbuffer. This can cause a noticeable stutter during gameplay.

Iterating every entity every frame may cost a little more, but it removes potential stalls.

Then again, I am an amateur at this so this could be completely wrong.

I’m not sure if you’re describing an actual performance issue you’re having due to structural changes or if you’re worried about potential performance issues. If you’re performing thousands of structural changes one at a time in a single frame then yes in that case there will definitely be a performance hit and you should probably go an alternate route like flags on components.

My personal preference would be to always design to the idea that you add a component to an entity to get a system to act on it. It’s how ECS was meant to work. With proper use of batch operations and command buffers you can do a lot to mitigate the costs of structural changes, and the payoff you get in code separation and readability is well worth it in my opinion. As always you should profile first before you try to write messier more performant code when you might not even need to.

2 Likes

I cant argue with the readability.

Also, I was describing both. I did some stress testing on one system, and the cost of moving memory were small, but not insignificant. I think I am obsessive with getting the most performance.

ExclusiveEntityTransaction;)

1 Like

Wow, I had no idea, thanks!

Adding or removing tags to an Archetype have zero impact on the main thread. It will just change the archetype description, not the data.

2 Likes

I’m not sure what you mean by this. If you add a tag component to an entity it changes that entity’s archetype which moves it to a new chunk.

If you add to a single Entity, yes, because it can be anywhere, and it needs to move to another Archetype/chunk.
But if you a the tag to an Archetype, and chunks are bound to just one Archetype, it just need to know that this whole chunk not have one more component tag, all the data can remain in the same space in memory.
It’s a smart DOTS optimization.

2 Likes

A tag is considered an empty component?

An empty component is called a tag.

public struct SomeUsefulTag : IComponentData
{
}