Millisecond timing?

Hi. I am trying to create a very simple program for Windows and hopefully Android as well. It is basically a stopwatch, but instead of hitting a button to start and hitting a button to stop, it will start when the button is pressed and stop when the button is released.

If I understand correctly, using Update it can be as far off as 16.6 ms. That would be perfectly fine for a lot of things, but I’m dealing with like 20-50 ms windows here, so 16.6 ms off isn’t quite cutting it. Is there some way to achieve better accuracy/precision? (Using Fire1 and Fire3 for X and square on Xbox and PS4 controllers, probably a much better way to do that but it really isn’t much of a concern, it does what I need.)

Oh, also, this may be the thing I’m timing, I’m not for certain, but occasionally the timer really seems like it adds 100ms or so. I don’t think it is my code causing it, but if someone sees something in these few lines of code that could cause it, please give me a heads up. Anyways, appreciate any responses, thanks. (Guess I should add that this problem occurs rarely(?) when I’m running it in the editor with like 2k-2.5k fps.)

using UnityEngine;
using UnityEngine.UI;

public class Timer : MonoBehaviour
{

    private float timePressed;
    private Touch touch;
    public Text timeHeld;

    // Update is called once per frame
    void Update()
    {

        if (Input.touchCount > 0)
        {
            Touch touch = Input.GetTouch(0);

            if (touch.phase == TouchPhase.Began)
            {
                timePressed = Time.time;
            }

            if (touch.phase == TouchPhase.Ended)
            {
                timeHeld.text = ((Time.time - timePressed).ToString("0.000"));
            }
        }

        if (Input.GetButtonDown("Fire3") || Input.GetButtonDown("Fire1"))
        {
            timePressed = Time.time;
        }
        if (Input.GetButtonUp("Fire3") || Input.GetButtonUp("Fire1"))
        {
            timeHeld.text = ((Time.time - timePressed).ToString("0.000"));
        }
    }
}

I believe you need to choose the correct tool to solve your requirements. If a key requirement is very precise timing, you should not use a game engine, but a perhaps a very fast UI engine. Unity might be made to fit your requirement here, but only by coincidence, not design, and probably not reliable.

One reason is that you are using Update() to track your button events. In essence, Update runs once every frame. The Problem: the time for each frame might be what you want, but it is not guaranteed to be. If something slows down your computer, the time between frames might be much more. You have seen this yourself when (for reasons unknown), Unity seems to add 100ms. Updating a canvas element, for example, can easily cost 100ms if the canvas is complex enough, or the processor low-powered. A Garbage Collection pass may also be triggered, and the GC time may also be added to the time. So if your release happens during such a slow frame, the overhead is added to your time.
A precise timer would start and stop e.g. by interrupt-driven routines: the button would generate an interrupt exactly on up and down so that you can mark down the time as it happens. Your routine above checks each pass through Update() if a press or release has happened in the intervening time since the last check. That’s not the same, but might be within spec if you manage to get the Interval between Updates small enough. But even then, Unity is not set up to guarantee precise Update() intervals, so Update() is not the right choice for precise time measurements.

Also note that Time.time does not read the system clock directly but holds the time at the beginning of the frame. It will not progress during frame processing.

So short answer: You will not be able to create a time measurement in Unity using Update() that has a reliable resolution at all, much less a reliable resolution better than 15ms.

1 Like

Okay, won’t lie, most of that went over my head. I knew the Update() being called once a frame would be a problem though. The odd 100ms or so added on top every now and then isn’t such a problem, can just discard those results.

I added an FPS counter a moment ago and seen that I’m actually getting about 250 fps instead of the 2000-2500 it is showing in the stats window on the editor. Kind of surprised by that as I have very little going on here and have a gtx-1070 and an i5-6600k oc’d. I suppose that is all sort of beside the point now though.

Unity is the only thing I’ve ever used, don’t have experience with anything else, but if Unity isn’t up to the task could you recommend something else? Was hoping I could just run it at a high enough frame rate that it’d be accurate enough, but I’m honestly not even for sure if Android is frame capped or anything. lol

Edit: Read it all again and most of it did not go over my head actually. I just sort of made it all more complicated in my head than what you said. Ha.

Well, for one thing if your computer has Unity Editor running it has a LOT going on while you run the app. It may only seem little because you only a single object and single script, but Unity still runs the entire game engine, plus Ediotr - and remember that it also updates those fields in Inspector, shows multiple other views, draws gizmos, keeps your project window synched with your file system etc. So there goes a lot of performance out of the window right there (and adds variability to frames).

Android, running on mobile will be even more of a challenge to keep precise time, since phones have crappy processors, are permanently strapped for memory, and have lots of other processes running in the background that steal time and therefore add imprecision to the frame time.

It comes down to your requirements. If your client needs precise timing, build a time keeper (from hardware, probably not that difficult if milliseconds are all that is required, an Arduino may do the trick), and use unity to read it (e.g. via USB or Bluetooth) and then display and persist the data. Unity can’t precisely measure time, because that is not what it was built for. Use something that was, and then use Unity’s strengths to further process the acquired data.

2 Likes

Okay, that is a lot.

Got me questioning all these games that require very precise timing now.

I’ll check those links. Thank you for all the info and the help. Much appreciated.

Maybe you can check your requirements. Few games have high precision requirements, as the average human response time to a visual stimulus is around 250ms. And most games use relative timing, exactly what you get from Update. Perhaps you explain your requirements and revisit your assumptions; often a much simpler solution can be arrived at simply because much of what you thought you needed was not really required (only nice to have)

1 Like

Honestly, this is going to sound goofy… but I’m just wanting to time different jump shots and their green windows on NBA 2k20. Lol. Based on the information I have seen, most of their jump shots are between like 400-600 ms and have a “green” (guaranteed make basically) window of something between like 20-50 ms depending on the shot and badges I believe.

Edit: With it running in the editor (should have just built the exe I suppose) my particular shot seemed to green between 448 ms and 480 ms, discarding the few shots that would outside of that, which I chalked up to lack of accuracy due to Update().

You could do all drawing on the video card with one single shader for your entire scene that handle all game drawing and UI; this will ensure you will have the speed you need.

Never create garbage to ensure consistency. You can load everything then GC.Collect() and don’t use code that can create garbage while game is running.

Time.realtimeSinceStartup returns value from system timer, I’ve used this at different points during the same frame for benchmarking - the docs say behaviour depends on hardware so this might not be useful if the value returned on what you’re targeting isn’t precise enough. Unity - Scripting API: Time.realtimeSinceStartup

@adehm Aside from the FPS counter I added which I was just using to see if I got a different result from the editor stats window, the code here is literally all there is to it. Well, the code, the main camera and the canvas.

@adamgolden I’ll check that out and see if it makes any kind of difference.

Thank you both.