I am using Job system to update many gameobjects’ transforms. I noticed that sometimes IJobParallelForTransform.Schedule reaches a overhead of milliseconds. The profiler showed that Schedule was blocked by worker thread. It looks like Schedule() was waiting for the job to finish.
Example codes of my job manager:
void LateUpdate()
{
handle2.Complete();
if (resultArray.IsCreated) resultArray.Dispose();
resultArray = new NativeArray<Data>(dataLength, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
var job1 = new Job1 { /*...*/ };
var job2 = new Job2 { /*...*/ };
Profiler.BeginSample("schedule");
handle1 = job1.Schedule(accessArray1);
handle2 = job2.Schedule(accessArray2, handle1);
Profiler.EndSample();
}
If its IJobParallelForTransform - its most likely a TAA marshalling cost. Bigger TAA length - higher cost.
There’s nothing can be done about it. You won’t receive much benefits if job is really simple.
What you want to do with data transformations TAA is something like this:
Sync to Entities → Run loads of complex TRS data mutations → Sync back to Transform
Or just running complex simulation in a job and sync’ing back.
This way marshalling cost will be lower than overall cost of data mutation.
One thing I haven’t tested with Entities 1.0+ is burst compiling IJobParallelForTransform jobs.
If its possible, you could try moving scheduling logic to the ISystem & burst compiling OnUpdate.
That should reduce cost of scheduling.
Hi @VergilUa , Thanks for your reply. Actually I am not using ECS. This is just for GameObjects and the number of transforms is 100-300. And I assume the “marshalling” you mentioned is the TransformAccessArray.Sort. I sometimes see this in profiler after modifying the TransformAccessArray but the time cost it introduces is negligible.
Overall my jobs run pretty fast, at about 0.08ms:
As shown above, the Schedule() wasn’t blocked by jobs and there aren’t much idle betwen jobs. However there are some frames when my main thread was blocked for more than 1 ms, and there is unreasonably long idle between jobs, as shown in my first reply.
A performance analysis of my job manager over 300 frames:
Most frames it only costs microseconds. There is one frame it reaches 0.5 ms and 1 frame it reaches 0.97 ms
That only applies if you perform that method call. Otherwise jobs are scheduled but not ran instantly (unless you call .Complete right away). So it shouldn’t matter for this case.
Its highly likely native side does some work beforehand.
Hard to tell without the sorces, but basically, its managed to native transfer cost.