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

Can no longer have ReadOnly BufferFromEntity in IJobChunk in 0.1.0-preview ?

Discussion in 'Entity Component System' started by Singtaa, Jul 30, 2019.

  1. Singtaa

    Singtaa

    Joined:
    Dec 14, 2010
    Posts:
    492
    So before today's update, I could use ReadOnly BufferFromEntity in IJobChunk. After upgrading to 0.1.0-preview, it gives error:
    If I remove the ReadOnly attr, it gives another error:

    Here's the full code that used to work in 0.0.12-preview.33:
    Code (CSharp):
    1.     [BurstCompile]
    2.     struct FillViewers : IJobChunk {
    3.         [ReadOnly] public ArchetypeChunkEntityType EntityType;
    4.         public ArchetypeChunkBufferType<SyncedEntityElement> SyncedEntityElement;
    5.         [ReadOnly] public BufferFromEntity<ViewerEntityElement> ViewerEntityBFE;
    6.  
    7.         public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) {
    8.             var entities = chunk.GetNativeArray(EntityType);
    9.             var syncedEntityBufferAccessor = chunk.GetBufferAccessor(SyncedEntityElement);
    10.             for (int i = 0; i < syncedEntityBufferAccessor.Length; i++) {
    11.                 var entity = entities[i];
    12.                 var syncedEntities = syncedEntityBufferAccessor[i];
    13.                 for (int j = 0; j < syncedEntities.Length; j++) {
    14.                     var viewers = ViewerEntityBFE[syncedEntities[j]];
    15.                     viewers.Add(entity);
    16.                 }
    17.             }
    18.         }
    19.     }
     
    Last edited: Jul 30, 2019
  2. Guerro323

    Guerro323

    Joined:
    Sep 2, 2014
    Posts:
    25
    You are writing (as you use the function Add()) in the buffer, and this can cause some problems when doing parallel jobs, if you want to fix that issue you can set the job as single threaded, or if you are sure your code is 100% safe then add the attribute [NativeDisableParallelForRestriction] to your 'BufferFromEntity<T>' variable.
     
    Singtaa likes this.
  3. Singtaa

    Singtaa

    Joined:
    Dec 14, 2010
    Posts:
    492
    Thanks! Yes in my specific case, safety is no concern. So either [NativeDisableParallelForRestriction] or [NativeDisableContainerSafetyRestriction] will do. I guess I just find it weird ReadOnly BufferFromEntity is being enforced now and not before.
     
  4. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    You could

    [DisableParallelForRestriction]
    public BufferFromEntity<ViewerEntityElement> ViewerEntityBFE;

    If you can gurantee for your game that no two buffers will be accessed by the parallel chunks being processed. Essentially you need to be certain there are no two ViewerEntityElement that point to the same entity in your game.

    If you can't gurantee it, then you can simply use ScheduleSingle instead of Schedule on the job. thus it will not run the job parallel thus it is safe to access any element by entity.


    None of this is a good solution... The real issue here, is that you are looking at the problem the wrong way. The best solution is to express it differently...


    The Safe by default & performant by default approach is to change it to a pull model. The destination data knows where it can copy it's data from. Reading can always be done safely in parallel. So that approach has the advantage of being inherently safe to multithread.

    Additionally this approach reduces false sharing for the multiple jobs running in parallel.
    https://en.wikipedia.org/wiki/False_sharing
    This can in fact be a massive performance problem if you do not invert how you try to solve the problem.
     
  5. jdtec

    jdtec

    Joined:
    Oct 25, 2017
    Posts:
    302
    Can you link an example, article or explain a bit more please?
     
  6. Singtaa

    Singtaa

    Joined:
    Dec 14, 2010
    Posts:
    492
    I think in my previous example, it would be to invert the roles of ViewerEntityElement and SyncedEntityElement. @Joachim_Ante makes a very good point about the RAM cache caveat, I never really thought about that.

    However, in my case, if you simply invert the roles (start with ViewerEntityElement and calc/pull the necessary data), the perf will go from O(n) to O(n^2) because pulling this way would require looking at all entities against all entities.