EndSimulationEntityCommandBufferSystem performance slow when instantiating entities from job

Hello, I have a job which instantiates an explosion entity when a fireball entity collides with another. I am getting very bad performance from this interaction. The StepPhysicsWorld is also very slow when instantiating these entitites. The performance of fireballs arcing through the air is also very bad. This does not seem to be related to the particles. How can I get better performance? Below is my profiler and my job.

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Physics;
using Unity.Physics.Systems;

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(StepPhysicsWorld))]
[UpdateBefore(typeof(EndFramePhysicsSystem))]
public partial class ApplyOnHitEffectJobSystem : SystemBase
{
    private StepPhysicsWorld m_StepPhysicsWorld;

    protected override void OnCreate()
    {
        m_StepPhysicsWorld = World.GetOrCreateSystem<StepPhysicsWorld>();
        RequireForUpdate(GetEntityQuery(new EntityQueryDesc
        {
            All = new ComponentType[] { typeof(ApplyOnHitEffect), typeof(ApplyAbilityEffect) }
        }));
    }

    protected override void OnStartRunning()
    {
        this.RegisterPhysicsRuntimeSystemReadOnly();
    }

    protected override void OnUpdate()
    {
        //Dependency.Complete();

        var applyOnHitEffectJob = new ApplyOnHitEffectJob
        {
            applyOnHitEffetFromEntity = GetComponentDataFromEntity<ApplyOnHitEffect>(true),
            applyAbilityEffectFromEntity = GetBufferFromEntity<ApplyAbilityEffect>(false),
        }.Schedule(m_StepPhysicsWorld.Simulation, Dependency);

        Dependency = applyOnHitEffectJob;

        //applyOnHitEffectJob.Complete();
    }

    [BurstCompile]
    public struct ApplyOnHitEffectJob : ITriggerEventsJob
    {
        [ReadOnly] public ComponentDataFromEntity<ApplyOnHitEffect> applyOnHitEffetFromEntity;
        public BufferFromEntity<ApplyAbilityEffect> applyAbilityEffectFromEntity;

        public void Execute(TriggerEvent triggerEvent)
        {
            // Initialize necessary variables to apply effects
            var effectEntity = Entity.Null;
            DynamicBuffer<ApplyAbilityEffect> targetEffectBuffer = new DynamicBuffer<ApplyAbilityEffect>();

            // Conditionally set value of variables to correct #
            if (applyOnHitEffetFromEntity.HasComponent(triggerEvent.EntityA) && applyAbilityEffectFromEntity.HasComponent(triggerEvent.EntityB))
            {
                effectEntity = applyOnHitEffetFromEntity[triggerEvent.EntityA].effect;
                targetEffectBuffer = applyAbilityEffectFromEntity[triggerEvent.EntityB];
            }
            else if (applyOnHitEffetFromEntity.HasComponent(triggerEvent.EntityB) && applyAbilityEffectFromEntity.HasComponent(triggerEvent.EntityA))
            {
                effectEntity = applyOnHitEffetFromEntity[triggerEvent.EntityB].effect;
                targetEffectBuffer = applyAbilityEffectFromEntity[triggerEvent.EntityA];
            }
            // If the values are not set, exit early.
            else
            {
                return;
            }

            // Apply the effect
            targetEffectBuffer.Add(new ApplyAbilityEffect { effect = effectEntity });
        }
    }
}

8419944--1113900--Fireball1.gif

There’s a few things I don’t know yet that make it hard to suggest anything. Are safety checks enabled? Is leak detection enabled? How many entities are you instantiating.

I’ll provide you with this link which may help you reduce the cost of instantiating entities: Latios-Framework/Documentation~/Optimization Adventures/Part 4 - Command Buffers 1.md at v0.5.7 · Dreaming381/Latios-Framework · GitHub

1 Like

I disabled safety checks and leak detection and I still get pretty similar performance characteristics. I am spawning between 8 and 200 entities depending on how long I hold the right trigger. Whether it is 8 or 200 I still get incredibly poor performance, but 200 is almost 3 times worse.

Edit: I will read and attempt to implement the page you sent me.

At those entity counts, that smells like job scheduling issues and not ECB playback performance. Can you post a Timelime view of the profiler?

I’m not sure what to highlight here, but that block on the right looks bad to me so I’ll zoom:

Ok. So not job scheduling. The link I sent may actually be applicable here.

Is entity journaling enabled? Also, do the entities you are instantiating have children?

Your main bottleneck here is GameObject instantiation. Most-likely your entities have either large companion GameObjects or alike (or lots of them in this case). That’s exactly what you see with @ Instantiate;

If you’re relying on GO’s & MonoBehaviours, make sure to re-use created objects / perform pooling technique on them.

As for the physics jobs, its better to see what takes most of the time. (Try deep profile)
Also, key question here, what collisions are being processed, and is there a way to reduce them?

Because if fireballs are physics objects, that’s not going to work (it will not scale properly).
If that’s the case, write arcing logic without physics simulation. E.g. by using physics queries instead of full collider collisions.

Also, as a workaround, you could try reducing physics frame time to reduce number of calls (e.g. to fixedDeltaTime ~0.03 instead of 0.02)

1 Like

Entity journaling is disabled. I think we may be narrowing down the problem. My entities have children and their children have children. This is a consequence of the way my abilities are authored. Disabling all of the children (rendering my fireball invisible) seems to improve performance quite a bit, but it’s still not great.
8420172--1113936--upload_2022-9-6_15-17-49.png

StepPhysicsWorld is still taking up huge portions of the frame

@VergilUa is 100% right about the instantiation issue. Forget the link I gave you. The real issue is that Trail Renderers and Particle Systems use Companion Game Objects, and instantiating those are slow. I don’t use any of that, so I didn’t recognize the profiler signatures.

There are four ways to move forward:

  1. Pool your effects, rather than instantiate and destroy entities.
  2. Use entity particles (I have an example of fireworks using this, and while I haven’t implemented it myself yet, have an idea for trails).
  3. Use VFX graph and events
  4. Use a custom compute shader and jobified mesh builder solution

As for the physics, I’m the wrong person to answer as I use my own custom physics solution that I can optimize myself.

1 Like

As per my previous post I am not directly using gameObjects but it may be that there are invisible companion gameObjects. I don’t know how to see those.

What do you mean it will not scale? DOTS can’t handle 200 colliders? Collisions are only happening when a fireball intersects with the ground and then the fireball is instantly destroyed. How is this so problematic? I’ll see about the rest of your post.

Okay, I’ll try these after work and see what I can get done. Thanks!

Depends on how conversion is done.

Its hard to tell what are those colliders after conversion. Are those static colliders, dynamic rigidbodies or something else. Overhead & costs may vary significantly.

Issues arise when colliders become in contact with each other. In case if such thing as “collision matrix” for Physics package exist - check if fireballs do not perform collisions with each other.

Haven’t used Physics package either, so its better to either check what those colliders are converted into.
Or ask on the related subforum.

As a sugestion, try authoring pure physic bodies first without overhead of GO’s.
Because it looks like a conversion / companion GO overhead issue.

In general, if hybrid approach is used, you’d want to separate visual layer from simulation / data layer.

Ideally, do something like:

  • Run physics & logic on pure entities;
    …- Simulate physics;
    …- Handle collisions etc;
  • At the end of simulation:
    …- Sync VFX objects to those entities → Trim / Create new instances;
    …- Align entities to objects;
    …- Sync TRS (position, rotation, maybe scale);

Here are the physics components on the fireball:

Here are the physics components on the explosion:
8420616--1113996--upload_2022-9-6_18-25-45.png

The explosion does not move so it does not have a physics body. The “Mixed…” Collides With collides with players/monster and the ground, but not other abilities. This ain’t my first rodeo… it’s like my 3rd, so thanks for checking.

I have reverted to representing the entities with spheres and flattening the hierarchy, so now the VfxFireBall and VfxExplosion have only one gameObject with no children, and the mesh renderer is directly on the main entity. It seems to have sped up performance quite a bit, but the physics step is still surprisingly slow. Here are my perf characteristics now:

Server:

Client:

Here’s a demonstration showing the frame drops:

8420622--1114011--Fireball2.gif

Here’s an example of me using a entities as particles that I whipped up. It’s got pretty good perf characteristics compared to instantiating and destroying gameobjects like I was doing. I guess I’ll wait until particles are actually supported to worry about making my game look nice lol. I don’t really want to worry about having caches of gameObjects on top of Entities.

8420739--1114041--Fireball3.gif

Better to just use DrawProcedural (we do that for trails for example) no need to use compute shaders here, which is actually will be slower than using raw DrawProcedural and calculating mesh right in vertex function (especially it performs better on consoles). The only bursted job required is for constructing effect data and filling command buffer (through Begin\EndWrite):wink:

2 Likes