Search Unity

Finding of how much time Unity takes in frame.

Discussion in 'Scripting' started by Deleted User, May 7, 2021.

  1. Deleted User

    Deleted User

    Guest

    Hello,
    I want to find out how much free time is left on core that Unity uses. As we know Unity is mostly single threaded and almost all operations that affect Unity objects in scene must be called from Unity thread.

    Accessing this thread is not a problem, it's enough to provide logic to MonoBehaviour.Update() so it can be run on Unity thread.

    I have lot's of background work that is run on other threads, and it's all working fine, the problem is synchronizing back to Unity. I would like to fill free time that is not used by Unity with synchronization logic yet I cannot find out how much free time there is.

    Time.deltaTime returns time of that whole frame took to render including sleep time.

    How to find out how much free time there is, or how long unity related logic do take?
     
    PutridEx likes this.
  2. What I would try: if you don't care about precise frame-finish (no matter if your stuff finishes in current frame or two frames from now or whatever), and I got the idea that this is your case, then you can measure time between end of LateUpdates. For example if you go for 60FPS, you have the rightfully feared 16.6ms plus change. If you arrive at LateUpdate and you still have a couple of ms left, then do some work, otherwise wait for next frame.

    Naturally, just throwing out thoughts... no idea if it would work, really.

    Obviously there is no API to measure the inner workings of Unity this way. There is for profilers, but obviously that doesn't work in release builds and it would be inefficient.

    edit: Or, maybe it would be better to measure your time between the beginning of the first
    Update
    (put a script earlier in the execution order list) and the
    yield WaitForEndOfFrame
    (or a LateUpdate on a script which is among the last in the execution order list in the settings).
    https://docs.unity3d.com/Manual/ExecutionOrder.html
     
    Last edited by a moderator: May 7, 2021
    rubcc95 likes this.
  3. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    I'm with Ninja. The biggest problem that I see with this is that there is no case, no matter how low you put the frame rate of your application in which you can safely say know you've "free time to fill not used by Unity MainThread". It is probably best to ask yourself why you think you need the main task this stop and if you really cannot do it in any of the time slots it offers you to carry out your tasks. Anyway, if you must have it stopped, you could sleep the mainthread where you know it would be safe and make all you Sync there. But I cannot think of how it could be done efficiently so that it would not be noticed on the screen with respect to the physics and other smooth movements, beyond the inevitable loss of frames if the sync time takes so long... Just another scrappy idea.

    Code (CSharp):
    1. //This should be a thread safe singleton probably
    2. public class MainThreadSync : MonoBehaviour
    3. {
    4.     [SerializeField] int _millisecondsToSync = 10;
    5.     public bool CanSync { get; private set; }
    6.  
    7.     void ForceSyncTime()
    8.     {
    9.         CanSync = true;
    10.         Thread.Sleep(_millisecondsToSync);
    11.         CanSync = false;
    12.     }
    13. }
    14.  
    15. void NotMainThreadMethod
    16. {
    17.     if(MainThreadSync.CanSync)
    18.         Sync();
    19. }
    20.  
     
    Last edited: May 7, 2021
  4. Deleted User

    Deleted User

    Guest

    rubcc95 It seems I may not have expressed myself clearly, I do not wish to stop Unity thread.

    My synchronization is done by providing Delegates to MonoBehaviour script so it can execute logic on Unity thread itself.


    If game runs with vsync it’s often have lower fps than user machine can provide for example: 60 fps capped 170 uncapped. Meaning Unity thread waits couple of ms for target fps, a time I wish to use.

    The point is I do not wish to overfill execution queue, because it would lead to fps drop. For that I need to know how much time there is.


    Lurking-Ninja your solution was a good path forward, I managed to find value that I need.

    Time from LateUpdate to Update of next frame is a time can be used as indicator of how much ms is free. It’s not that precise and gets glitchy when frame do take too much time.

    I have set Update to run as soon as possible (-1000 in script order), and LateUpdate as late as possible (+1000 in script order).

    Thanks for the help.

    Cheers.
     
    Lurking-Ninja likes this.
  5. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    It doesn't matter what you configure, you only move its position with respect to the other lateUpdate/Update methods;

    If you are going to use the Ninja approach, I recommend that you do it in a coroutine with the aforementioned yield WaitForEndOfFrame, since all the rendering proccess is done AFTER LateUpdate and that may solve a good part of the glitches you are encountering.
    I would also make sure to avoid the synchronization process if in that frame you have destroyed or deactivated an object, since this is done still after EndOfFrame and it can take it's time (You can call it at Update, the object will not be effectively destroyed/disabled until the end of frame).
    For this I would avoid using Behavior.enabled or Object.Destroy directly in my application and would create my two own methods which would deactivate the synchronization when the object is going to be destroyed / disabled.
     
    Last edited: May 7, 2021
  6. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,555
    Worth a mention:
    https://docs.unity3d.com/ScriptReference/Time-realtimeSinceStartup.html

    Edit: You can get the result at the start of a function then compare it with the result at the end for benchmarking specific blocks of code - I've done this without issue. So you could in theory grab the time at the end of your last function call and know how much time since the previous frame it took from that point until your first call in the subsequent frame. You could then use this to approximate how much dead time to expect after the current frame, clamping whatever result to make sure you never overflow whatever limits you have in mind (i.e. maybe always process at least 1 of something each frame, but do more when expected real time remaining exceeds what you allotted for the frame based on when the next frame should begin less the anticipated inter-frame duration..).
     
    Last edited: May 7, 2021
  7. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
  8. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    Well, it allows you to calculate it, but I think our guy really knows perfectly how to calculate it already so yeah, that's no the topic target.
     
  9. Deleted User

    Deleted User

    Guest

    rubcc95 tested out span of time form WaitForEndOfFrame to Update and it is more accurate than using LateUpdate. Thanks for the tip about Destroying/Deactivating objects, I will take that into account during final design.

    Are you aware of any other logic that runs after WaitForEndOfFrame?

    On the screenshot we can see that we have active ExampleOperation that takes ~10 ms, and EndOfFrame -> Update Time give us information that we have ~5.872 ms left to use. Of course considering that next frame will take a similar amount of time to render.
    2021-05-07_18-17-22_Development_Test.png
     
  10. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222