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. Dismiss Notice

nativeThreadIndex vs JobsUtility.MaxJobThreadCount

Discussion in 'Entity Component System' started by nicolasgramlich, Feb 27, 2020.

  1. nicolasgramlich

    nicolasgramlich

    Joined:
    Sep 21, 2017
    Posts:
    231
    Hey everyone,

    I've been using a custom "RandomSystem" in order to get "proper" random numbers in a
    JobComponentSystem.Entities.Foreach
    . Everything was fine until the number of my entities went above
    128
    . I was making the (false) assumption that the
    nativeThreadIndex
    of the
    ForEach
    would somehow be limited to
    JobsUtility.MaxJobThreadCount
    .

    The docs say this:
    So my idea was to just change:
    Code (CSharp):
    1. var random = randomArray[nativeThreadIndex];
    to
    Code (CSharp):
    1. var random = randomArray[nativeThreadIndex % JobsUtility.MaxJobThreadCount];
    and call it a day, but I'm wondering if there is a better solution for this kind of problem, because I'm sure it's going to pop up in some shape or form again soon. :eek:

    Thanks :)

    Code (CSharp):
    1. public class RandomSystem : ComponentSystem {
    2.     public NativeArray<Random> randomArray;
    3.  
    4.     protected override void OnCreate() {
    5.         var randomArray = new Random[JobsUtility.MaxJobThreadCount];
    6.         var seed = new System.Random();
    7.  
    8.         for (var i = 0; i < JobsUtility.MaxJobThreadCount; ++i) {
    9.             randomArray[i] = new Random((uint) seed.Next());
    10.         }
    11.  
    12.         this.randomArray = new NativeArray<Random>(randomArray, Allocator.Persistent);
    13.     }
    14.  
    15.     protected override void OnDestroy() {
    16.         randomArray.Dispose();
    17.     }
    18.  
    19.     protected override void OnUpdate() { /* Nothing */ }
    20. }
    Code (CSharp):
    1. public class UnitAttackTargetSystem : JobComponentSystem {
    2.     protected override JobHandle OnUpdate(JobHandle inputDependencies) {
    3.         var randomArray = World.GetExistingSystem<RandomSystem>().randomArray;
    4.  
    5.         return Entities.WithAll<Foo>.WithNativeDisableParallelForRestriction(randomArray).ForEach((int nativeThreadIndex, Entity entity, int entityInQueryIndex) => {
    6.             var random = randomArray[nativeThreadIndex];
    7.  
    8.             // ...
    9.  
    10.             /* Write back the random struct so that next time it won't be the same: */
    11.             randomArray[nativeThreadIndex] = random;
    12.         }).Schedule(inputDependencies);
    13.     }
    14. }
     
    Buffes likes this.
  2. Icewave

    Icewave

    Joined:
    Mar 1, 2013
    Posts:
    1
    I've just run into this myself, and am now very confused. In the tests I've done, nativeThreadIndex is always equal to entityInQueryIndex, given the wording of nativeThreadIndex i believe its mean't to give a value unique to the thread, that wont go above MaxJobThreadCount, but right now, its just giving entityInQueryIndex...

    Is it bugged? Is unity passing entityInQueryIndex twice by mistake? have i missed something?


    Code (CSharp):
    1.                     if(nativeThreadIndex != entityInQueryIndex)
    2.                         UnityEngine.Debug.Log(string.Format("{0} - {1}", nativeThreadIndex, entityInQueryIndex));
    never prints anything

    Code (CSharp):
    1.                     if(nativeThreadIndex == entityInQueryIndex)
    2.                         UnityEngine.Debug.Log(string.Format("{0} - {1}", nativeThreadIndex, entityInQueryIndex));
    always prints (the same value for both variables)

    Using entities package 0.8.0 preview8

    EDIT: The problem seems to be because both entityInQueryIndex & nativeThreadIndex are present, if only one is present the value is as expected.

    EDIT2: I'm having some success avoiding the issue by defining "int entityInQueryIndex" at the begining of the lambda, and "in int nativeThreadIndex" at the end, important point is the "in" decoration. If both are put "int", or both are "in int", both values will be the same.
     
    Last edited: Apr 12, 2020
  3. unity-freestyle

    unity-freestyle

    Joined:
    Aug 26, 2015
    Posts:
    45
    Nice catch, this indeed happens if you use them both and out of order in the lambda declaration.
    nativeThreadIndex
    should always come after
    entityInQueryIndex
    and their values will be correct.

    Code (CSharp):
    1.  .ForEach((int entityInQueryIndex, int nativeThreadIndex, Entity entity, ref Translation translation, ref Rotation rotation) => {})
    2.  
     
  4. Occuros

    Occuros

    Joined:
    Sep 4, 2018
    Posts:
    284
    It seems this is still the case in Entities 0.16
     
    nicolasgramlich likes this.
  5. as_nau

    as_nau

    Joined:
    Oct 11, 2020
    Posts:
    30
    Faced the same issue in Entities 0.16

    It seems if I put entityInQueryIndex first:
    Code (CSharp):
    1. .ForEach((int entityInQueryIndex, int nativeThreadIndex,  ref Translation trans)
    then both parameters will be equal to nativeThreadIndex.

    If nativeThreadIndex first:
    Code (CSharp):
    1. .ForEach((int nativeThreadIndex,  int entityInQueryIndex, ref Translation trans)
    then both parameters will be equal to entityInQueryIndex.

    But workaround proposed by Icewave works for me:
    Code (CSharp):
    1. .ForEach((int entityInQueryIndex,  ref Translation trans, in int nativeThreadIndex)
     
    Last edited: Jan 5, 2021
    jasons-novaleaf, Occuros and nyanpath like this.
  6. reeseschultz

    reeseschultz

    Joined:
    Apr 1, 2018
    Posts:
    21
    jasons-novaleaf likes this.