Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Event Chains: ECB Sync Points or ComponentDataFromEntity[Entity] ?

Discussion in 'Entity Component System' started by toomasio, Dec 1, 2020.

  1. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    195
    Hello,

    Just wondering what you guys have been using for event chains and what would be most efficient. I started off solving this issue by creating my own "in" and "out" ECBs inside custom ComponentSystemGroups. I would send "events" by adding component data, then depending on tags, it would add other components as it moves down the stack. But then found out about sync points...so having a bunch of these buffers in my pattern is probably not a good idea? Will these ECB sync points eventually become more efficient anyways? This pattern seems to be the proper "Unity" way of doing things based on the YouTube talks.

    Then I came across @tertle 's Event system and started migrating some of my event chains to that system... to solve the sync point issue. I did hit a slight snag though as writing to ComponentDataFromEntity[Entity] using generic classes cannot be done in parallel...so I would probably need to loop through event readers paired with Entities.ForEach Lambda inside the reader loop....BUT you can't do generic Lambda functions either!...so I would need to rewrite a bunch of boilerplate code for every event chain.

    I am also not someone who writes 500-1000 lines of code in one system. I like to spread all my logic around into as small pieces as possible (50-100 lines max). This is what I am loving about Unity's DOTS so far, but I also keep running into these code patterns that don't seem to mesh well with DOTS.

    Just wondering what some of you guys have done to combat this event chain issue.

    Thanks,
     
  2. reeseschultz

    reeseschultz

    Joined:
    Apr 1, 2018
    Posts:
    21
    ECBs are meant to reduce sync points. You may want to take a look at the documentation. Here's a snippet:

    You can use entity command buffers (ECBs) to queue up structural changes instead of immediately performing them. Commands stored in an ECB can be played back at a later point during the frame. This reduces multiple sync points spread across the frame to a single sync point when the ECB is played back [my emphasis].

    Each of the standard ComponentSystemGroup instances provides a EntityCommandBufferSystem as the first and last systems updated in the group. By getting an ECB object from one of these standard ECB systems, all structural changes within the group occur at the same point in the frame, resulting in one sync point rather than several. ECBs also allow you to record structural changes within a job. Without an ECB, you can only make structural changes on the main thread.
    I get excellent performance adding and removing components at runtime via ECBs. Works great. To me, it sounds like you should be more open to using all the tools in your toolkit. You don't have to write all of your code one way. There's no Code Heaven where there is final judgment of syntax choice or usage of goto taking place.

    If you find a gap somewhere, just use another tool to fill the gap. Sounds like, for now, it may be the ECB in your case. Generally speaking, most of the stuff in code I vowed I'd never do, I have now done at this point. Writing in C# is one such example, lol.
     
  3. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    195
    Thanks for your detailed answer. I know what ECBs do but sometimes you need a chain of events happening in a single frame. This can sometimes cause a long chain of custom ECBs...which can create multiple sync points per frame. Is creating a bunch of your own custom ECBs frowned upon or is this standard Unity pattern that will continue to be improved under the hood?
     
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    If you have lots of small systems, then you don't want many sync points unless all your code is going to be main thread (which will be more viable when Bursted systems arrive).
    I wouldn't expect too much more of a speedup for structural changes. While they are not as fast as they can be, and I have written custom command buffers to speed them up somewhat, copying all the components of structurally changed entities is still expensive. It is fine for low frequency.
    Unity will eventually roll out enabled/disabled components which use bitmasking to rule out disabled entities in chunk iteration. You can emulate this by adding a bool to each component.
    Nothing wrong with this approach either (using containers to store propagating data payloads). However, it isn't so much the issue with generic classes as much as it is writing to CDFE in parallel. You need [NativeDisableParallelForRestriction] to do that, and you better know what you are doing because it is extremely unsafe.
     
    toomasio likes this.
  5. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    195
    This would solve a lot of the issues I am bringing up here. I actually started off doing an "IsActivated" bool pattern at the beginning... but heard having dormant components sitting on entities can also be inefficient? Not sure exactly where I heard this but it caused me to rethink how I did things at the time. Maybe it's good to have them in certain situations.
     
  6. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    Welcome to the world where the optimal solution depends on the amount, frequency, and circumstances of the operations relative to everything else. :p
    But really, I would need to know a lot more about your project to really provide any more direction.
     
    toomasio and reeseschultz like this.