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. We’re making changes to the Unity Runtime Fee pricing policy that we announced on September 12th. Access our latest thread for more information!
    Dismiss Notice
  3. Dismiss Notice

Bug profiling bug in coroutine 2020.1

Discussion in 'Editor & General Support' started by laurentlavigne, Sep 12, 2020.

  1. laurentlavigne


    Aug 16, 2012
    this will spam the console with

    Code (CSharp):
    1. while (true)
    2.         {
    3.             UnityEngine.Profiling.Profiler.BeginSample("fill the input arrays");
    4.             //
    5.             emitterZero.CopyTo(emitterValues, 0);
    6.             Vector4 _tmp = new Vector4();
    7.             int skippy=0;
    8.             for (int i = 0; i < settings.Length; i++)
    9.             {
    10.                 foreach (var e in settings[i].emitters)
    11.                 {
    12.                     var pos = World2Grid(e.transform.position);
    13.                     _tmp.Set(i == 0 ? 1 : 0, i == 1 ? 1 : 0, i == 2 ? 1 : 0, i == 3 ? 1 : 0);
    14.                     if (pos.x >= 0 && pos.x < size.x && pos.y >= 0 && pos.y < size.y)
    15.                         emitterValues[pos.x + pos.y * size.x] += e.value * _tmp;
    16.                     if (skippy % 500 ==0)
    17.                         yield return null;
    18.                     skippy++;
    19.                 }
    20.             }
    21.             //
    22.             UnityEngine.Profiling.Profiler.EndSample();
  2. PraetorBlue


    Dec 13, 2012
    Interesting. I'm not sure this is a bug per-se, simply because the way iterator methods are implemented in C#, separation of the samples over a yield statement means the sample statements are actually executed in different method calls.

    C# iterators (which coroutines are an example of) are actually compiled into a class that implements IEnumerator. All of the code in your coroutine is basically split up into sections based on yield statement boundaries to create a state machine. Every time MoveNext is called on the object, the code runs one of those sections, and the state of the machine changes to whatever code block is after the yield statement.

    Here's a better explanation:

    In other words.. the error you're getting is actually correct, as your sampler begin and end are technically not happening in the same stack frame.

    What would be the goal of sampling a coroutine like this anyway? If it worked, the sample would include the entire frame duration for all of the frames that the coroutine execution is split over. A large majority of that time is likely... well.. the entire rest of the game running, not this method.
    laurentlavigne likes this.
  3. laurentlavigne


    Aug 16, 2012
    Ok that's interesting.
    I seem to remember that it used to work and allowed to conveniently profile a coroutine, that must have been in between the yield.
  4. MartinTilo


    Unity Technologies

    Aug 16, 2017
    @PraetorBlue is correct and any return between a profiler Begin and End call would cause trouble. If you used ProfilerMarker.Auto it'd be fine (i.e. not throw errors and end the sample on leaving the scope/returning automatically) but the profiler marker wouldn't pic up profiling on returning to the coroutine again because that would need a new call to Auto.

    So really, in this case you'd ought to call EndSample before the yield return and BeginSample after.