Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

-solved-

Discussion in 'Entity Component System' started by tertle, May 7, 2019.

  1. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    -edit- solved, can be ignored. unrelated to post.

    So I finally managed to solve it after nearly 24 hours of debugging, but it turned out the issue was completely unrelated to this post.

    If you're interested, the crash was from a very rare unexpected NaN which was caused by floating point rounding in a completely separate algorithm that propagated through a couple of other algorithms.

    Slowing down the application or changing system order (with different systems/jobs) caused the error to occur significantly less frequently which is why I was not able to diagnose it correctly for a long time. I finally caught it after writing a simulation that I could leave running for ages while constantly spitting out data.

    -original-

    My editor started consistently locking up today and after debugging I narrowed it down to this system

    Code (CSharp):
    1.  
    2. protected override void OnCreate()
    3. {
    4.     this.hideQuery = this.GetEntityQuery(new EntityQueryDesc
    5.     {
    6.         None = new[] { ComponentType.ReadOnly<Hidden>(), },
    7.         Any = this.hideTypes,
    8.     });
    9.  
    10.     this.showQuery = this.GetEntityQuery(new EntityQueryDesc
    11.     {
    12.         None = this.hideTypes,
    13.         All = new[] { ComponentType.ReadOnly<Hidden>() },
    14.     });
    15. }
    16.  
    17. protected override void OnUpdate()
    18. {
    19.     this.Entities.With(this.hideQuery).ForEach(entity =>
    20.     {
    21.         this.PostUpdateCommands.AddComponent(entity, default(Hidden));
    22.  
    23.         if (this.EntityManager.HasComponent<RenderBounds>(entity))
    24.         {
    25.             this.PostUpdateCommands.SetComponent(
    26.                 entity,
    27.                 new RenderBounds { Value = OutOfBounds });
    28.         }
    29.         else if (this.EntityManager.HasComponent<MeshRenderer>(entity))
    30.         {
    31.             this.EntityManager.GetComponentObject<MeshRenderer>(entity).enabled = false;
    32.         }
    33.     });
    34.  
    35.     this.Entities.With(this.showQuery).ForEach(entity =>
    36.     {
    37.         this.PostUpdateCommands.RemoveComponent<Hidden>(entity);
    38.  
    39.         if (this.EntityManager.HasComponent<RenderBounds>(entity))
    40.         {
    41.             this.PostUpdateCommands.RemoveComponent<RenderBounds>(entity);
    42.         }
    43.         else if (this.EntityManager.HasComponent<MeshRenderer>(entity))
    44.         {
    45.             this.EntityManager.GetComponentObject<MeshRenderer>(entity).enabled = true;
    46.         }
    47.     });
    48. }
    You can ignore the MeshRenderer stuff, none of my entities when testing this had them.

    When using just a single entity toggling between hiding/showing it has no issue. When using 512 entities Unity will freeze up like it's infinitely looping (max cpu usage).

    I thought it might be some issue constantly removing (then Unity adding RenderBounds) but just to test I decided to try rewrite it with Chunk Iteration and for some reason completely solves the crashes.

    Code (CSharp):
    1. protected override void OnCreate()
    2. {
    3.     this.hideQuery = this.GetEntityQuery(new EntityQueryDesc
    4.     {
    5.         None = new[] { ComponentType.ReadOnly<Hidden>(), },
    6.         Any = this.hideTypes,
    7.     });
    8.  
    9.     this.showQuery = this.GetEntityQuery(new EntityQueryDesc
    10.     {
    11.         None = this.hideTypes,
    12.         All = new[] { ComponentType.ReadOnly<Hidden>() },
    13.     });
    14. }
    15.  
    16. protected override void OnUpdate()
    17. {
    18.     this.HideEntities();
    19.     this.ShowEntities();
    20. }
    21.  
    22. private void HideEntities()
    23. {
    24.     var chunks = this.hideQuery.CreateArchetypeChunkArray(Allocator.TempJob);
    25.  
    26.     var entityType = this.GetArchetypeChunkEntityType();
    27.  
    28.     for (var chunkIndex = 0; chunkIndex < chunks.Length; chunkIndex++)
    29.     {
    30.         var chunk = chunks[chunkIndex];
    31.         var entities = chunk.GetNativeArray(entityType);
    32.  
    33.         for (var i = 0; i < chunk.Count; i++)
    34.         {
    35.             var entity = entities[i];
    36.  
    37.             this.PostUpdateCommands.AddComponent(entity, default(Hidden));
    38.  
    39.             if (this.EntityManager.HasComponent<RenderBounds>(entity))
    40.             {
    41.                 this.PostUpdateCommands.SetComponent(
    42.                     entity,
    43.                     new RenderBounds { Value = OutOfBounds });
    44.             }
    45.             else if (this.EntityManager.HasComponent<MeshRenderer>(entity))
    46.             {
    47.                 this.EntityManager.GetComponentObject<MeshRenderer>(entity).enabled = false;
    48.             }
    49.         }
    50.     }
    51.  
    52.     chunks.Dispose();
    53. }
    54.  
    55. private void ShowEntities()
    56. {
    57.     var chunks = this.showQuery.CreateArchetypeChunkArray(Allocator.TempJob);
    58.  
    59.     var entityType = this.GetArchetypeChunkEntityType();
    60.  
    61.     for (var chunkIndex = 0; chunkIndex < chunks.Length; chunkIndex++)
    62.     {
    63.         var chunk = chunks[chunkIndex];
    64.         var entities = chunk.GetNativeArray(entityType);
    65.  
    66.         for (var i = 0; i < chunk.Count; i++)
    67.         {
    68.             var entity = entities[i];
    69.  
    70.             this.PostUpdateCommands.RemoveComponent<Hidden>(entity);
    71.  
    72.             if (this.EntityManager.HasComponent<RenderBounds>(entity))
    73.             {
    74.                 this.PostUpdateCommands.RemoveComponent<RenderBounds>(entity);
    75.             }
    76.             else if (this.EntityManager.HasComponent<MeshRenderer>(entity))
    77.             {
    78.                 this.EntityManager.GetComponentObject<MeshRenderer>(entity).enabled = true;
    79.             }
    80.         }
    81.     }
    82.  
    83.     chunks.Dispose();
    84. }
    I think the logic and output here is exactly the same? Yet this has no issues.

    Anyone have any idea why? I don't like not knowing why something is crashing, or why something fixed the crash.
     
    Last edited: May 8, 2019
  2. Singtaa

    Singtaa

    Joined:
    Dec 14, 2010
    Posts:
    492
    I'm testing your first system with 512 entities, but am not reproducing the CPU lock up. How are you toggling the comps on the entities?

    Current test code:
    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Mathematics;
    3. using Unity.Rendering;
    4. using Unity.Transforms;
    5. using UnityEditor;
    6. using UnityEngine;
    7.  
    8. public struct Hidden : IComponentData { }
    9. public struct Hide : IComponentData { }
    10.  
    11. public class TestSystem : ComponentSystem
    12. {
    13.     private EntityQuery hideQuery;
    14.     private EntityQuery showQuery;
    15.  
    16.     protected override void OnCreate()
    17.     {
    18.         var hideTypes = new[] { ComponentType.ReadOnly<Hide>() };
    19.         this.hideQuery = this.GetEntityQuery(new EntityQueryDesc
    20.         {
    21.             None = new[] { ComponentType.ReadOnly<Hidden>(), },
    22.             Any = hideTypes,
    23.         });
    24.  
    25.         this.showQuery = this.GetEntityQuery(new EntityQueryDesc
    26.         {
    27.             None = hideTypes,
    28.             All = new[] { ComponentType.ReadOnly<Hidden>() },
    29.         });
    30.     }
    31.  
    32.     protected override void OnUpdate()
    33.     {
    34.         this.Entities.With(this.hideQuery).ForEach(entity =>
    35.         {
    36.             this.PostUpdateCommands.AddComponent(entity, default(Hidden));
    37.  
    38.             if (this.EntityManager.HasComponent<RenderBounds>(entity))
    39.             {
    40.                 this.PostUpdateCommands.SetComponent(
    41.                     entity,
    42.                     new RenderBounds { Value = new AABB() });
    43.             }
    44.             else if (this.EntityManager.HasComponent<MeshRenderer>(entity))
    45.             {
    46.                 this.EntityManager.GetComponentObject<MeshRenderer>(entity).enabled = false;
    47.             }
    48.         });
    49.  
    50.         this.Entities.With(this.showQuery).ForEach(entity =>
    51.         {
    52.             this.PostUpdateCommands.RemoveComponent<Hidden>(entity);
    53.  
    54.             if (this.EntityManager.HasComponent<RenderBounds>(entity))
    55.             {
    56.                 this.PostUpdateCommands.RemoveComponent<RenderBounds>(entity);
    57.             }
    58.             else if (this.EntityManager.HasComponent<MeshRenderer>(entity))
    59.             {
    60.                 this.EntityManager.GetComponentObject<MeshRenderer>(entity).enabled = true;
    61.             }
    62.         });
    63.     }
    64. }
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using Unity.Entities;
    4. using Unity.Mathematics;
    5. using Unity.Rendering;
    6. using Unity.Transforms;
    7. using UnityEditor;
    8. using UnityEngine;
    9.  
    10. public class TestScript : MonoBehaviour
    11. {
    12. #if UNITY_EDITOR
    13.     [MenuItem("MyMenu/Add Hide")]
    14.     static void AddHide()
    15.     {
    16.         var EntityManager = World.Active.EntityManager;
    17.         var entities = EntityManager.GetAllEntities();
    18.         for (int i = 0; i < entities.Length; i++)
    19.         {
    20.             EntityManager.AddComponentData<Hide>(entities[i], new Hide());
    21.         }
    22.     }
    23.  
    24.     [MenuItem("MyMenu/Remove Hide")]
    25.     static void RemoveHide()
    26.     {
    27.         var EntityManager = World.Active.EntityManager;
    28.         var entities = EntityManager.GetAllEntities();
    29.         for (int i = 0; i < entities.Length; i++)
    30.         {
    31.             EntityManager.RemoveComponent<Hide>(entities[i]);
    32.         }
    33.     }
    34. #endif
    35.  
    36.     void Start()
    37.     {
    38.         for (int i = 0; i < 512; i++)
    39.         {
    40.             var EntityManager = World.Active.EntityManager;
    41.             EntityManager.CreateEntity(typeof(RenderBounds));
    42.         }
    43.     }
    44.  
    45. }
    46.  
     
    Last edited: May 7, 2019
  3. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I've also managed to run the offending system without any locks. Even went to 10k entities and all fine (a bit slow :p)
    I've just spawned entities with a RenderMesh (cube)
    I'm running Unity 2019.2.0a14 on Windows
     
  4. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    That's the thing. I can't replicate it either in a small solution but a simple return stops unity locking up (or rewriting it as Chunk Iteration) which is what is perplexing me.

    I have no other systems that rely on RenderBounds which might conflict (there are only 4 systems total in this current project).

    The components are toggled in these jobs.

    Code (CSharp):
    1.  
    2. /// <summary>
    3. /// Iterate a queue of entities and remove the <see cref="T"/> component from them.
    4. /// </summary>
    5. /// <typeparam name="T">The component type to remove.</typeparam>
    6. public struct RemoveComponentJob<T> : IJob
    7.     where T : struct, IComponentData
    8. {
    9.     /// <summary>
    10.     /// The queue of entities to remove the <see cref="T"/> component from.
    11.     /// </summary>
    12.     public NativeQueue<Entity> Entities;
    13.  
    14.     /// <summary>
    15.     /// The <see cref="EntityCommandBuffer"/>.
    16.     /// </summary>
    17.     public EntityCommandBuffer EntityCommandBuffer;
    18.  
    19.     /// <inheritdoc />
    20.     public void Execute()
    21.     {
    22.         while (this.Entities.TryDequeue(out var entity))
    23.         {
    24.             this.EntityCommandBuffer.RemoveComponent<T>(entity);
    25.         }
    26.     }
    27. }
    28.  
    29. /// <summary>
    30. /// Iterate a queue of entities and add a default <see cref="T"/> component to them.
    31. /// </summary>
    32. /// <typeparam name="T">The component type to add.</typeparam>
    33. public struct AddComponentJob<T> : IJob
    34.     where T : struct, IComponentData
    35. {
    36.     /// <summary>
    37.     /// The queue of entities to add the <see cref="T"/> component to.
    38.     /// </summary>
    39.     public NativeQueue<Entity> Entities;
    40.  
    41.     /// <summary>
    42.     /// The entity command buffer.
    43.     /// </summary>
    44.     public EntityCommandBuffer EntityCommandBuffer;
    45.  
    46.     public void Execute()
    47.     {
    48.         while (this.Entities.TryDequeue(out var entity))
    49.         {
    50.             this.EntityCommandBuffer.AddComponent(entity, default(T));
    51.         }
    52.     }
    53. }
    54.  
    Also 2019.2.0a14

    Thanks for testing.
     
    Last edited: May 7, 2019
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    Ok, managed to crash it again with new code. Probably just a coincidence then that it started crashing a lot less frequently after changing.

    I really don't know what issue is then. Is it an issue with Hybrid Renderer when constantly removing RenderBounds or another system of mine - but there are only 2 other systems in this package project and neither of them have any dependencies on any of this so I find that unlikely.
     
  6. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
  7. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    Can you provide a sample project file that crashes?
     
  8. Singtaa

    Singtaa

    Joined:
    Dec 14, 2010
    Posts:
    492
    So the chunk iteration version also crashes? Can you check the memory usage of Unity in Task Manager while it happens? @sngdan beat me to it haha
     
  9. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    I'm in process of trying to create a small replica for a bug report (assuming I determine that it isn't one of my systems.)

    Itcrashed first time since making original post (about 2.5 hours) vs crashing within 30 seconds of playing scene but yes it did crash. I can't seem to force it to crash at the moment which is even more frustrating but it did definitely crash once.

    Memory is 950MB only growing very slowly (hasn't crashed yet). I did check it before when it crashed and I had GB of free memory at the time.

    -edit-

    just got it to crash again

    upload_2019-5-7_15-13-28.png

    Definitely not running out of memory

    -edit2-

    left it 30 seconds while posting this screenshot and the editor recovered at some point during posting this.
    Maybe it's not crashing, maybe a system is just taking a hell of a long time to process randomly.
     
  10. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    Yep that's it.

    It's not crashing. Something is just taking 5-10 seconds to process randomly. Ok that gives me something to investigate.

    -edit-

    i should add this is with burst on or off and safety checks on or off.

    ok definitely crashed when i tried to 'stall' it with the profiler attached
     
    Last edited: May 7, 2019
    GilCat likes this.
  11. Singtaa

    Singtaa

    Joined:
    Dec 14, 2010
    Posts:
    492
    Yeah like @GilCat said, if you want to get to the bottom of this, we can take a look at your sample proj (if reproducible).
     
    Last edited: May 7, 2019
  12. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    Yeah I was going to ask what the profiler was telling you about those seconds of freeze but I guess you can't.
    I notice that after running that system I can't get a clean exit from the editor.
     
  13. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    Don't really want to bump this but just wanted to thank you two for trying to help out.

    I finally managed to solve it after nearly 24 hours of debugging, but it turned out the issue was completely unrelated to this post.

    If you're interested, the crash was from a very rare unexpected NaN which was caused by floating point rounding in a completely separate algorithm that propagated through a couple of algorithms.

    Slowing down the application or changing system order (with different systems/jobs) caused the error to occur significantly less frequently which is why I was not able to diagnose it correctly for a long time. I finally caught it after writing a simulation that I could leave running for ages while constantly spitting out data.
     
    GilCat and Singtaa like this.