Search Unity

Benchmarking tag component

Discussion in 'Entity Component System' started by 5argon, Apr 19, 2019.

  1. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    The concern is whether to tag and cause chunk data movement then query tagged chunks, or just if on the data. I did some benchmarking. (details : https://gametorrahod.com/tag-component/) Ticks is C# StopWatch ticks (10000 = 1ms)

    Adding tags via Concurrent ECB (Not Burst compiled) -> Playback on main thread to cause chunk data movement. It approaches 23 ticks per entity when large enough. (39 at 100 entities, 23 over 1000) So maybe, we could estimate by multiplying 39~23 by amount of tag change needed in a frame for how many ticks it take from your total 166,600 ticks available in the frame.

    Screenshot 2019-04-19 12.01.33.png

    Iterating to work (minus a number, Bursted) on tagged entities.

    Screenshot 2019-04-19 12.02.06.png
    Iterating to `if` check and work (Bursted) on entities that would be tagged, without tagging.

    Screenshot 2019-04-19 12.02.23.png
    Comparing `if` vs iterating through tagged entities. `if` is losing when less entities are tagged because it had to if on all entities that are not going to be worked on.

    Screenshot 2019-04-19 12.02.49.png

    The "upfront payment" of tagging is not as high as I thought, tagging/untagging 100 entities every frame would add around 2500 ticks. In the same frame `if` may be better but over several frames it should pay off. (The game should not change tags that often anyways) Even with equal number of `if = true` case and fully tagged, tagging will still save some `if` cost. (Without `if` you could get better SIMD assembly)
     
    Last edited: Apr 20, 2019
    lclemens, rsodre, GilCat and 8 others like this.
  2. Deleted User

    Deleted User

    Guest

    Thank you so very much for all of your ECS blog-posts.
    They are very useful.
     
    5argon likes this.
  3. BrendonSmuts

    BrendonSmuts

    Joined:
    Jun 12, 2017
    Posts:
    86
    You do great work man, always get something useful from you blog posts. Thanks!
     
    5argon likes this.
  4. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    One thing to note is that EntityManager.AddComponent(ComponentGroup group, ComponenentType type); based add component is significantly faster. It acts on whole chunks and for tag components specifically it does not need to move the chunks data at all.

    This is a common case for reactive systems.
     
  5. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,129
    Hi @5argon, do u have benchmark for non-tag component?
     
  6. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    Yes, the ecs equivalent of 'To be or not to be'. I constantly flip flop on this. Thanks for the benchmarks.

    This is awesome. I've been hoping for something like this but had no idea it was already in there.
     
  7. Deleted User

    Deleted User

    Guest

    How would you use it in a real case scenario?
     
  8. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    It's useful for event entities where they all need to be activated/removed in groups every frame.
    So an event management system will add a tag to all new event entities to activate them (allows other systems to process them), and also delete previously activated entities. My collision event system works this way.
    Currently I'm iterating individual entities just to add a tag to each one using command buffer.
    Now I can tag the chunk which makes this whole process a single op.
     
    jdtec and Deleted User like this.
  9. Deleted User

    Deleted User

    Guest

    I see now. Thank you.
     
  10. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Not planning to do at the moment, but I think it wouldn't make a difference mainly in chunk data allocation. It needs to prepare SOA of your non-tag component in the destination chunk according to chunk's capacity.

    If adding to a single Entity this should be a small difference depending whether the destination chunk already exist or not, but with EntityManager EntityQuery whole chunk Add/Remove API it means the whole chunk doesn't need to reform SOA space for the new archetype.

    I have covered EntityManager batch API somewhat here. So I think in total this 4 could be done on a whole chunk basis : Add, AddShared, Remove, Destroy. (AddShared could be performed with data! Thanks to how SCD works on the chunk that isn't really the actual data)

    I have been utilizing the fact that EntityQuery you use with EntityManager batched API could be attached with SCD filter. Suddenly I could do selective and fast add/remove/destroy by setting up SCD permutations to group them up from since they was created.

    I have 10000 of things to show but only a subset (1000) of them is visible+processed at any given time (governed by Process tag component) and this subset move forward from 0,1000, 2000, 3000, ... until the end. So for each 1000 entities I add Group SCD with integer 1~10, when it is time to remove all Process of the previous 1000 entities and add to the next 1000 at once, I could achieve that with 1 Add and 1 Remove with filtered EntityQuery instead of 2000 iteration.

    The Destroy with EntityQuery had been useful for cleaning up all the "message" entity every frame since I have no system to tag who had processed the message. It's like throwing away chunks. (They are entities to represent input in a frame, so I could unit test faking input by creating the input entity)
     
    Last edited: Apr 20, 2019
    FROS7, eizenhorn and Deleted User like this.