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
-
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.
-
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). EntityQuery DebuggerTypeProxy could return both chunks and entities.
-
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
-
Entities as tree view (parent-child hierarchy)
-
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:
- 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?
DOTS API
-
SharedComponentIndexFromEntity<>. We should be able to access Entity’s SDC index from a job. I have a good usecases for this feature.
-
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:
[assembly: InternalsVisibleTo("Unity.Entities.Editor")]
[assembly: InternalsVisibleTo("Unity.Entities.Editor.Tests")]
[assembly: InternalsVisibleTo("Unity.Entities.Hybrid")]
[assembly: InternalsVisibleTo("Unity.Entities.Hybrid.Tests")]
[assembly: InternalsVisibleTo("Unity.Entities.StaticTypeRegistry")]
[assembly: InternalsVisibleTo("Unity.Entities.CPlusPlus")]
[assembly: InternalsVisibleTo("Unity.Editor")]
[assembly: InternalsVisibleTo("Unity.Authoring")]
[assembly: InternalsVisibleTo("Unity.Tiny.IO")]
[assembly: InternalsVisibleTo("Unity.Tiny.Scenes")]
[assembly: InternalsVisibleTo("TestStaticTypeRegistry")]
[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.
- 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?
-
NativeHashSet - native equivalent of HashSet. Very useful container type. Should be available in the core.
-
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.
-
NativeHashMap.ParallelWriter memory growth. When you exceed its capacity, it throws an exception. Sometimes you cannot predict capacity before job execution.
-
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.
Summary
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!