Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Small quantities, plural types and Unity-unrelated optimization.

Discussion in 'Entity Component System' started by qqqqqqqqqqqqqqqqq1, Jul 2, 2020.

  1. qqqqqqqqqqqqqqqqq1

    qqqqqqqqqqqqqqqqq1

    Joined:
    Jun 3, 2020
    Posts:
    13
    I've been considering implementing DOTS for my project, but I do have a couple questions.

    First, if there are thousands of instances and those instances aren't MonoBehaviour related, is there a way to benefit from the boost? Consider a system which has a Dictionary with thousands of instances of a certain class, these classes are independent of Unity (no UnityEngine etc. dependencies). Does DOTS benefit me in that case? What if that class, does contain a field, which is of a type that requires UnityEngine?

    Second, how well does DOTS scale on small amounts of items of different types. What if I have 1000 of different types of objects, each type has 100 Entities, thats total of 100 000 Entities. Will this work about as well as 100 000 Entities of a single type?

    Third, and what about just a small number? If there's only 10 Entities. I know that the improvement is probably immeasurably tiny in that context, but I'm interested in the gist of it. How well does DOTS scale on insanely small amount of objects?
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,993
    Yes. DOTS optimizes for data layout, multithreading, and optimized assembly. While moving away from the C#/C++ interop is a gain in and of itself, it isn't the only gain DOTS receives.
    Instances of a class? No. But if they were structs, yes. You could use a NativeHashmap instead of a Dictionary and run your algorithms that use it in Burst.
    DOTS handles this case pretty well. You can run into main thread scheduling bottlenecks in 2019.3. 2020.1 offers a little more headroom in that regard.
    At this scale, you aren't worried about performance. You are worried about size. Well, Project Tiny exists, so DOTS scales well there too.
     
  3. qqqqqqqqqqqqqqqqq1

    qqqqqqqqqqqqqqqqq1

    Joined:
    Jun 3, 2020
    Posts:
    13
    1. I've seen a handful of "benchmarks" online, however they don't represent numbers, we have to guess-calculate frames per second which is not indicative of performance, are there any official numbers regarding speed in Unity's own testing case?

    2. What happens in case where computer doesn't struggle with normal numbers of items? Consistent low-delay 120 FPS. Is there any other benefit? Does the delay between frames go down? Is the CPU usage in general lower? Is the input lag lower?

    3. Considering following code, which code would be the most preferential for speed and its consistency? Case 1, Case 2 or Case 3?
    Code (CSharp):
    1. namespace test
    2. {
    3.     public class test
    4.     {
    5.  
    6.         public NativeHashMap<string, Food> foods;
    7.         public NativeHashMap<string, Meal> meals;
    8.      
    9.         public Dictionary<string, MealX> xmeals;
    10.  
    11.      
    12.         void GetSomething()
    13.         {
    14.             // Using NativeHashMap (planned)
    15.             var case1a = foods["cheese"].mealid;
    16.             dynamic case1b = meals[case1a].name;            // This now contains a Meal.name item
    17.             // or
    18.             dynamic case2_result = meals[foods["cheese"].mealid].name;            // This now contains a Meal.name item
    19.  
    20.             // Using references (now)
    21.             var case3 = xmeals["cheese"].food.name;    // This now contains a Meal.name item, and is a reference
    22.         }
    23.     }
    24.  
    25.     public struct Food
    26.     {
    27.         public int mealid;
    28.         public string something;
    29.     }
    30.  
    31.  
    32.     public struct Meal
    33.     {
    34.         public int id;
    35.         public string name;
    36.     }
    37.  
    38.     public class FoodX
    39.     {
    40.         public string name;
    41.     }
    42.  
    43.     public class MealX
    44.     {
    45.         public FoodX food;
    46.     }
    47.  
    48. }
    Because of (struct) NativeHashMap, I cannot use references, I can definitely work around it. But the issue is performance. Is the performance benefit granted from NativeHashMap outweighing the double-accessing I'd have to perform to get the same value from NativeHashMap compared to Dictionary? The pseudo-code above is provided as an example, don't sweat the readability.
     
  4. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Mixing is always tricky. There is no reason for strings to be using System.String, you can use
    NumberedWords or NativeString for a significantly more efficient representation based on what you are actually using it for.
     
  5. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,993
    1) Numbers are always use-case specific, but you can find some pretty compelling numbers in this video:

    2) Lower CPU usage, possibly, assuming you are GPU-bound or something. Input lag has more to do with architecture than CPU performance if you have a good framerate. ECS gives you a lot of control over this. It was trivial to switch to n-1 rendering for my game, which increased input lag by a frame but improved performance due to needing one less sync point and transform system update (which is really expensive for me).
    3) The code doesn't make a whole lot of sense. What problem are you actually trying to solve. In DOTS, the right solution is very problem-specific. The first thing I would try to do when working with DOTS is get rid of any unnecessary string logic that I can. If the string is never going to be displayed on screen or logged, there's probably a better alternative.
     
  6. qqqqqqqqqqqqqqqqq1

    qqqqqqqqqqqqqqqqq1

    Joined:
    Jun 3, 2020
    Posts:
    13
    I'm trying to access the same data with structs. I can use Dictionary and access to variable once like this:
    myDict["hotdog"].name;
    or I would have to access two variables from NativeHashMap like this:
    meals[foods["hotdog"].mealid].name;
    . Aside from readability, which would perform better? Forsaking 1 access to Dictionary would force me to use 2 accesses to Struct due to how logic is shaped in my game. 1x Dictionary<> vs. 2x NativeHashMap to access the data and not break the logic.

    To not break logic in my game, I can only choose between two:
    foods["cheese"].mealid;

    Where
    Dictionary<string, Meal>

    or
    meals[foods["cheese"].mealid].name;

    Where both are
    NativeHashMap<T, T1>
    .

    The keys and values will be different, this is just a demo.
    Lets say that Dictionary would be accessed about 1000 times a second. Would it even be worth to change it over to NativeHashMap in exchange for inconvenience?

    I assume integers and enums are okay.
     
    Last edited: Jul 10, 2020
  7. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,993
    I don't understand your logic about needing two NativeHashMaps instead of one Dictionary. But Bursted NativeHashMap lookups are several times faster than Dictionary lookups.

    Way faster.
     
    qqqqqqqqqqqqqqqqq1 likes this.