IJobForEach across two different archetypes with one to many relationship

I have two entity archetypes (tables) with a one to many relationship between them.The first has each entity contain a dynamic buffer of radiation values. The second has each entity contain component data to store things like the peak value of the radiation associated to it and a radiation index component used as a sort of foreign key in order to maintain the one to many association.

As far as I understand, I don’t want to be using a component system because I don’t want to run this job in start or update but instead based on some event somewhere else in my app for a monobehaviour to respond to and therefore schedule and complete this job.

I have code that works but it doesn’t burst compile because of my use of the entity manager in a job and I’m really unsure about whether my approach is even very performant in the first place.

[BurstCompile]
public struct PeaksCalculationJob : IJobForEach<RadiationIndex, Peak, PeakIndex, Cummulative>
{
    [ReadOnly] public NativeArray<Entity> simulationSphere;

    public void Execute (ref RadiationIndex radiationIndex, ref Peak peak, ref PeakIndex peakIndex, ref Cummulative cummulative)
    {
        // managed code that doesn't burst compile
        EntityManager entityManager = World.Active.EntityManager;
        Entity simulationSurface = simulationSphere[radiationIndex.value];
        DynamicBuffer<Radiation> radiationOnThisSurface = entityManager.GetBuffer<Radiation> (simulationSurface);

        // what I want to achieve
        for (short i = 0; i < radiationOnThisSurface.Length; i++)
        {
            if (peak.value < radiationOnThisSurface[i])
            {
                peak.value = radiationOnThisSurface[i];
                peakIndex.value = i;
            }

            cummulative.value += radiationOnThisSurface[i];
        }

        cummulative.value /= 1000;
    }
}

How can I improve this code/approach and ensure I’m squeezing out as much performance as I can. What rookie mistakes am I making here?

You can’t directly access the EntityManager or DynamicBuffers from another thread. If you need to make structural changes (Add/Remove components or entities) you have to pass in an EntityCommandBuffer which will create a sync point and cannot be BurstCompiled right now, see the samples for examples of that.

If you just need to access a dynamic buffer you need to pass in a BufferFromEntity to the job, which you do with GetBufferFomEntity when you’re creating the job:

    struct WriteToBuffer : IJobForEach<Data>
    {
        [NativeDisableParallelForRestriction]
        public BufferFromEntity<BufferType> bufferFromEntity;

        public void Execute(ref Data c0)
        {
            var buffer = bufferFromEntity[someEntity];
            // ...
        }
    }

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        inputDeps = new WriteToBuffer
        {
            bufferFromEntity = GetBufferFromEntity<BufferType>(false),
        }.Schedule(this, inputDeps);

        return inputDeps;
    }

You need the [NativeDisableParallelForRestriction] attribute to be able to write concurrently to the buffer from multiple threads. Just make sure you know what you’re doing and aren’t trying to write to the same index from different threads. If you can’t accommodate that you can use .ScheduleSingle to force your job to run on a single thread.

From what I get out of your description you can have all that in just one Entity. That entity would have buffer Radiation and components Peak, PeakIndex, and Cumulative then you just run a IJobFoeach_BCCC reading from Radiation and writing on the other components. And that will be BurstCompiled.

Hi @GilCat , this used to be the case for the project but the radiation arrays would end up repeating across a lot of the data. Our memory usage on just the pure numbers alone was reaching 10gb. So we want to reduce repeating data by storing the Radiation Buffer on separate entities and then accessing the right one by the using the RadiationIndex componentdata. This is the context behind my one to many relationship.

The code @Sarkahn_1 posted seems like an ideal solution from what it looks like. Would that implementation work with the burst compiler?

Yes, as long as you’re not using an EntityCommandBuffer (which will work eventually, but not yet) it will benefit from Burst.