Search Unity

Feedback My thoughts about current state of DOTS

Discussion in 'Data Oriented Technology Stack' started by supron, Sep 12, 2019.

  1. supron


    Aug 24, 2013
    This post is a continuation of my first feedback post. All of my thoughts arose during DotsUI development. Some of them may be incorrect or be a result of my lack of knowledge. I'll divide my post into several parts - code debugging, entity debugger and DOTS API.

    Code debugging

    1. Show entity name in all DebuggerTypeProxy (ArchetypeChunk etc.). Despite the fact that name is editor-only, it's still more useful than index/version. Currently, we are forced to jump constantly from editor Entity Debugger to IDE and memorize all of the numbers.

    2. There should be DebuggerTypeProxy for EntityQuery. Just like you made it for ArchetypeChunk or EntityManager. ArchetypeChunk contains only a fraction of the query result. Also, archetypes may differ a lot. In example we can have 30 entities with unique archetypes in one query. It's hard to debug these in IJobChunk (you have access only to the one chunk) and it's hard to debug them in the component system (requires additional code to return NativeArray<ArchetypeChunk>). EntityQuery DebuggerTypeProxy could return both chunks and entities.

    3. Ability to "deparallelize" job system. Debugging parallel code is hard. Breakpoints are caught by different threads in a non-deterministic order. I'd like to uncheck a simple checkbox to turn all workers off and execute code on the main thread. It's also useful to simulate low-end hardware and single-threaded environments (like WebGL). Being able to control workers count is another idea that came to my mind while I was writing this.

    Entity Debugger

    1. Entities as tree view (parent-child hierarchy)

    2. System hierarchy form component POV. I think it's a good idea to display systems hierarchy form component point of view. You select a component, and you see only the systems that have this component in queries. It could also show access type (r/w/rw). Like this:

    3. Taking detailed snapshots of the entire world update frame. This one is big, but I wanted to share my thoughts anyway. Similar to the frame debugger, enabling DOTS snapshot would capture system updates, queries, scheduled jobs etc. It could display which system scheduled a job, what are in-out dependencies and which job blocked resource (causing WaitForJobGroupID).

    Currently detecting why is one job waiting for another, is one of the hardest parts of the code optimization. It's easy to forget that component can be marked as read-only. Especially when you prototyping larger system. Maybe Unity can detect RW access in job/system that doesn't need it?


    1. SharedComponentIndexFromEntity<>. We should be able to access Entity's SDC index from a job. I have a good usecases for this feature.

    2. Make EntityComponentStore (and other internals) public. There are people who like to play with low level stuff. We could make better API proposals if we were able to play with bare bones. When the idea of SharedComponentIndexFromEntity came to my mind I tried to implement it by myself, but "internal" modifier quickly killed my enthusiasm. Other reasons are user-made editor tools for ECS. I already said that in my older thread about burst and its internal types. If you want the community to contribute, you have to open these types.

    I think it's a part of the larger problem with asmdefs. Developer should be able to block access to internal types, but also left the possibility to access these types from another assembly, without modyfing the main package. Look at the Unity.Entities/AssemblyInfo.cs:

    Code (csharp):
    2. [assembly: InternalsVisibleTo("Unity.Entities.Editor")]
    3. [assembly: InternalsVisibleTo("Unity.Entities.Editor.Tests")]
    4. [assembly: InternalsVisibleTo("Unity.Entities.Hybrid")]
    5. [assembly: InternalsVisibleTo("Unity.Entities.Hybrid.Tests")]
    6. [assembly: InternalsVisibleTo("Unity.Entities.StaticTypeRegistry")]
    7. [assembly: InternalsVisibleTo("Unity.Entities.CPlusPlus")]
    8. [assembly: InternalsVisibleTo("Unity.Editor")]
    9. [assembly: InternalsVisibleTo("Unity.Authoring")]
    10. [assembly: InternalsVisibleTo("Unity.Tiny.IO")]
    11. [assembly: InternalsVisibleTo("Unity.Tiny.Scenes")]
    12. [assembly: InternalsVisibleTo("TestStaticTypeRegistry")]
    13. [assembly: InternalsVisibleTo("Unity.Entities.PerformanceTests")]
    This is a symptom of a problem. Imagine more assemblies in the ecosystem and maintenance process. This design completely blocks user-made packages from work at the same level and quality as unity-made. I'm not talking about the full access to any type from any runtime assembly. I'm talking about breaking the rules for the very specific reason like writing editor tools, or low-level extensions.

    3. Parent system (again). I already mentioned it in my old post, but since I implemented ConvertToEntity system for my UI, it became really painful. I'm using the parent system for my RectTransforms, but I implemented my own hierarchy update job. LocalToWorld::UpdateHierarchy job is executed every frame even though I don't need it. I can't simply remove unnecessary components (LocalToParent and LocalToWorld), because Parent system doesn't work without them. LocalToWorld::UpdateHierarchy is fast, but it's still noticeable in the profiler with large UI hierarchies:

    This problem is not easy to solve. LocalToWorld::UpdateHierarchy assumes that children always have LocalToParent and LocalToWorld components. It's obvious - performance reasons. I'd like to hear if Unity is going to make parent system more generic, or should we implement our own systems for other types of parent-child relations?

    4. NativeHashSet<T> - native equivalent of HashSet<T>. Very useful container type. Should be available in the core.

    5. EntityManager API overloads for different native containers. Currently EntityManager/EntityCommandBuffer takes only NativeArrays (and casted NativeLists). I'm using a lot of NativeQueues (they have very efficient parallel writer) to store entities for further tasks, like adding components. Converting queue to array is an unnecessary step. Even better if you add NativeHashSet with EM/ECB overloads.

    6. NativeHashMap.ParallelWriter memory growth. When you exceed its capacity, it throws an exception. Sometimes you cannot predict capacity before job execution.

    7. Component systems performance. Let's be honest. Performance of the C# code without burst is very poor. A lot of code in ECS core is written in pure C# and this lack of low-level optimization is seen in the profiler. Scheduling few jobs with queries takes way more time than it should. I'd like to know if there are plans to improve performance outside of jobs code? I'm thinking about both ECS core and user-written code.


    For the past 3 months, I learned a lot about ECS development. In a few words - I like it. I'm really looking forward for the next package updates (especially pure dots/tiny). Thanks to the whole Unity development team. You did a great job!
    rocar, Jes28, Seb-1814 and 9 others like this.
  2. larsbertram1


    Oct 7, 2008
    nice and well structured post. i am not into dots but hope people who are will read it.
    well done.
  3. tertle


    Jan 25, 2011
    Good well thought out post. Just a couple of minor points of my own.

    Was a feature they said was coming a long time ago but never materialized. While I personally haven't run into a situation where I really needed it, I can totally see use cases for users who develop a different way to me.

    I feel like if you're doing such fine grain work you should probably be using IJobChunk anyway, however I can see little drawback/harm of including it.

    Yeah this is a huge issue for me as well. I actually wrote a class that hacks in internal access for myself to various packages by adding my own assembly to the AssemblyInfo on recompile (for SRP in particular)

    Can basically mimic this with an empty struct but no reason not to have a dedicated container for this. Very common requested feature for a long time.

    I reckon you can nearly always determine an upper bound. However allocating a few MB of memory just because it's an upper bound when in practice you only need a few KB of memory is not great. Maybe we need a slightly less performant variation that can grow.
  4. DreamingImLatios


    Jun 3, 2017
    A use case that I've run into is when EntityA has a component which holds a ref to EntityB. I might be iterating all EntityAs but want to look up the shared component index of EntityBs.

    @supron Excellent post by the way. I think it is really important that debugging one or many Burst jobs single or multithreaded should be accessible without having to modify code. There's going to be times when a user wants to debug everything single-threaded and no Burst, and then there's going to be times when a user wants to debug a select few jobs single-threaded without Burst and leave everything else Burst and multithreaded because its not fun to drag a machine to a crawl just to debug a borked job or two.
    GilCat likes this.
  5. Joachim_Ante


    Unity Technologies

    Mar 16, 2005
    In 2020.1 we will add support for settings JobsUtility.workerThreadCount = 0; which executes jobs immediately. We will expose a menu item in the editor to aid with debugging.

    Thanks for the post. Good read.
  6. Vincenzo


    Feb 29, 2012
    @Joachim_Ante What is keeping the workerThreadCount variable from making it into 2019.4 LTS or preferably 2018.4 LTS?
    We are heavily blocked by having this as a missed feature, our company rents many core servers ( 32 cores/64 threads) and runs multiple game servers on them, each unity instance is spawning 64 job threads that fight for the server cores and heavy thread contention is happening with a lot of useless context switches.
    Something has to be done, and we cannot wait for 2020.1 which in our case means 2020.4 LTS.
    wobes likes this.
  7. mike_acton


    Unity Technologies

    Nov 21, 2017
    > I'd like to hear if Unity is going to make parent system more generic, or should we implement our own systems for other types of parent-child relations?

    No, the transform system components are only intended to capture transform-related data. Not any other parent-child relationships. Not for any other kind of organizational use.
    eizenhorn and supron like this.