Search Unity

Profiling inside burst jobs

Discussion in 'Burst' started by jdtec, Aug 9, 2019.

  1. jdtec

    jdtec

    Joined:
    Oct 25, 2017
    Posts:
    302
    I need accurate timings for different parts of a burst job. Is there a way to get time in ticks/ms in a Burst job?

    I've already surrounded the job with Time.realtimeSinceStartup and complete calls to measure overall job time but I need more detail.

    I've tried deep profiling but it's frankly unusable on my setup. It crashes half the time (including literally crashing OSX just now) or exceeds data limits.

    It's pretty difficult to split up the job unfortunately so hoping someone has some ideas about getting a time measurement in some way...?
     
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    I've encountered similar situations and I'd love to be wrong but as far as I'm aware, the answer is No.

    My solution is to break up the internal of large jobs and bench them separate (it's still 1 job.)
    Let me give a quick example as it makes much more sense.

    Code (CSharp):
    1. public void Execute(Entity entity, int team, float3 position, float radius, float2 forward, float fieldOfView)
    2. {
    3.     // ...
    4.     var computer = new VisibilityPolygonComputer(positionScaled, radiusScaled);
    5.  
    6.     var hits = this.GetHits(position, radius);
    7.  
    8.     // Add occluder from hits
    9.     for (var i = 0; i < hits.Length; i++)
    10.     {
    11.         // ..
    12.         visibility.AddCircleOccluder(localCenter, localRadius, body);
    13.     }
    14.  
    15.     // ..
    16.  
    17.     var observedObstructions = new NativeHashMap<Entity, RigidBody>(hits.Length, Allocator.Temp);
    18.     computer.Compute(polygon, observedObstructions);
    19.  
    20.     var visit = this.GetCircleMapper(controllerEntity, position.xz, radius, observerHistory);
    21.     var line = new LineDrawing<CircleMapper>(visit);
    22.     var draw = new RasterizeTriangles<LineDrawingCircleMapperT>>(line);
    23.  
    24.     // ..
    25.  
    26.     for (var i = 0; i < observedObstructions.Length; i++)
    27.     {
    28.         // ..
    29.         draw.Draw(localPosition, p1, p2);
    30.     }
    31. }
    This is just a very basic snippet of a part of a very large job (compiles to something like 40k lines of assembly) but I breakup the logic into separate structs base on a specific task.

    Code (CSharp):
    1. public struct VisibilityPolygonComputer : IDisposable
    2.  
    3. public struct CircleMapper : IMapper
    4.  
    5. public struct LineDrawing<T> : ILine
    6.     where T : struct, IMapper
    7.  
    8. public struct RasterizeTriangles<T>
    9.     where T : struct, ILine
    I then use Unity's performance testing package to test the performance of each thing separately, both with and without burst.

    -edit-

    for example here is a simple job for my compute performance test

    Code (CSharp):
    1.         [BurstCompile]
    2.         private struct ComputeJob : IJob
    3.         {
    4.             public VisibilityPolygonComputer Computer;
    5.  
    6.             public void Execute()
    7.             {
    8.                 this.Computer.Compute(new NativeList<float2>(Allocator.Temp), new NativeHashMap<Entity, RigidBody>(128, Allocator.Temp));
    9.             }
    10.         }
    Code (CSharp):
    1.         [TestCase(10, 1)]
    2.         [TestCase(100, 1)]
    3.         [TestCase(10, 100)]
    4.         [TestCase(100, 100)]
    5.         [TestCase(10, 1000)]
    6.         [TestCase(100, 1000)]
    7.         [Performance]
    8.         public void ComputeTestBurst(int count, int instances)
    9.         {
    10.             VisibilityPolygonComputer[] computer = new VisibilityPolygonComputer[instances];
    11.             NativeArray<JobHandle> handles = new NativeArray<JobHandle>(instances, Allocator.Temp);
    12.  
    13.             Measure.Method(() =>
    14.                 {
    15.                     for (var i = 0; i < instances; i++)
    16.                     {
    17.                         handles[i] = new ComputeJob { Computer = computer[i] }.Schedule();
    18.                     }
    19.  
    20.                     JobHandle.CompleteAll(handles);
    21.                 })
    22.                 .SetUp(() =>
    23.                 {
    24.                     // setup
    25.                     // ..
    26.                 })
    27.                 .CleanUp(() =>
    28.                 {
    29.                     // cleanup
    30.                     // ..
    31.                 })
    32.                 .Run();
    33.  
    34.             handles.Dispose();
    35.         }
    Giving me a nice little little performance report of a single method used within a job.

    upload_2019-8-9_17-24-13.png
     
    Last edited: Aug 9, 2019
    CodeSmile, bb8_1, mkracik and 3 others like this.
  3. jdtec

    jdtec

    Joined:
    Oct 25, 2017
    Posts:
    302