Search Unity

Hybrid Sample and GetComponent

Discussion in 'Entity Component System' started by Ziboo, Mar 21, 2018.

  1. Ziboo

    Ziboo

    Joined:
    Aug 30, 2011
    Posts:
    356
    Hi,

    I'm looking at the Hybrid sample, and I was wondering the overhead "GetComponent" can have when you do it on a "prefab entity".

    Is it the same as a regular GetComponent from Monobehavior ?
    Maybe "GameObjectEntity" caches thoses component ?
    Can we call it everyframe ?

    Thanks
     
  2. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    EntityManager.GetComponent is a bit faster than GameObject.GetComponent performance.

    However in ECS the important part is that you can get massive speedups by avoiding GetComponent calls in the common cases. Like when iterating over a set of active objects and performing some behaviour every frame.
    Like this:
    https://github.com/Unity-Technologi...cs-full-on-performance---icomponentdata--jobs

    The performance difference compared to GetComponent calls is massive. Essentially this pattern is zero overhead when lots of entities are involved while GetComponent actually does quite a bit of work. It's really at the center of the Component System.

    Now EntityManager.GetComponent / EntityManager.SetComponent is still really useful. The pattern where it is useful is really just after instantiating an entity it is common that you want to set some component values. Thats exactly when you would usually use EntityManager.SetComponent...
     
    itsarjunsinh and asethi like this.
  3. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,129
    @Joachim_Ante, will it have high cost at initialization stage as I see the example uses dependency injection? From what I understand, dependency injection needs reflection that has quite high cost.
     
  4. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,335
    Code (CSharp):
    1.     // IJobProcessComponentData is a simple way of iterating over all entities given the set of required compoenent types.
    2.     // It is also more efficient than IJobParallelFor and more convenient.
    3.     [ComputeJobOptimization]
    4.     struct RotationSpeedRotation : IJobProcessComponentData<Rotation, RotationSpeed>
    5.     {
    6.         public float dt;
    7.  
    8.         public void Execute(ref Rotation rotation, [ReadOnly]ref RotationSpeed speed)
    9.         {
    10.             rotation.Value = math.mul(math.normalize(rotation.Value), math.axisAngle(math.up(), speed.Value * dt));
    11.         }
    12.     }
    which part does the "set of required component type" ? what's the limit of that filter?
     
  5. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    IJobProcessComponentData<Rotation, RotationSpeed>

    edit: what is unclear is, if this also allows subtractive Components
     
  6. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    We have optimized the injection code a lot. Basically we cache the results and at runtime frame to frame the injection code really just does the minimal thing, using just simple low level unsafe APIs.

    Pretty sure its actually faster than using GetComponentGroup from API actually... Because it allows us to cache more data...
     
  7. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    You can use
    [RequireComponentTagAttribute] to put additional component requirement constraints and you can use
    [RequireSubtractiveComponentAttribute] to put additional subtractive component requirements...

    You simply put them on the job struct and everything will work magically...
     
  8. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    This declares the minimum required set of components for the ComponentGroup.
    IJobProcessComponentData<Rotation, RotationSpeed>

    [RequireComponentTagAttribute] & [RequireSubtractiveComponentAttribute] lets you define additional ones.

    Also public void Execute(ref Rotation rotation, [ReadOnly]ref RotationSpeed speed)

    [ReadOnly] has an impact. It actually improves parallelism between jobs. eg. if you have two systems reading from RotationSpeed they can run in parallel if both are declared as [ReadOnly]. If they are default read/write, the jobs will be chained with dependencies. (Other jobs can still run in parallel of course but deeper dependency chains usually result in less parallelism)
     
  9. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,335
    Oh that is lovely how what we learn with job applies in system. In fact the way one programs a job is quite similar to the way a system is programmed.
    I was going to drill into the limitation of component filter but I realize that if I need 20 filters it probably means I need to break up my systems more, right?
     
  10. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    As a general rule 1-2 jobs per system is a good idea. The advantage of splitting into many systems and components is that you can in a simple modular way plugin new functionality.
     
    asethi likes this.
  11. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,335
    I skipped a beat here, go back a little, what's the connection between # of jobs and # of components in a filter?
     
  12. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    ;) I also get the feeling that it goes a bit left and right.

    @laurentlavigne do you have actually a specific case you want to solve or is it a theoretical question?

    It’s a bit hard to understand what exactly you are after. I do not think there is a limit to the components you can filter. I can not think of a Szenario, where you would need as many as 20 filters, subtractivecomponent can help when filtering and also if it gets too much, you could just add an empty component that functions as a “tag”