Sign in to follow this  
VanillaSnake21

How to properly get delta time on modern hardware?

Recommended Posts

I'm just doing some optimization on my framework and would like to start multithreading it, however as of now the only way I found how to keep time that was somewhat reliable was winapi QPC functions for high rez timers, however I'm having to lock my cpu to a single core as a result. I've also just read an article saying that it's ill advised to used QPC for low rez things like game logic and instead use timeGetTime. I've rewritten my code as such but timeGetTime() - currentTime always seems to return zero. I think it's in a different thread and just executing my code in less than an ms. So I would like to know the definitive answer as to how to do this properly on multicores.

Share this post


Link to post
Share on other sites

> winapi QPC

 

Make sure to not mix nanoseconds/microseconds/etc. with milliseconds.

Also, there's no guarantee that each core will have the same value returned by QueryPerformanceCounter().

 

> I've rewritten my code as such but timeGetTime() - currentTime always seems to return zero.

 

Well, those two seems to be the same thing, the current time.

 

Also, did you make a multi-theaded main loop or are you creating a particular thread to execute just a brief code? If doing multi-thread, the usual is to make the main loop multi-threaded, and each thread has their own track of the time. Physics threads, for example, **usually** run with fixed delta time (16 milliseconds). It seems that you are doing the second, however, creating a thread in the middle of the main loop and mixing timers of both threads (?).

 

> So I would like to know the definitive answer as to how to do this properly on multicores.

 

There's on definitive answer. That pretty much depends how you are making your main loop (and how you are makin the thread, as I mentioned above).

Share this post


Link to post
Share on other sites
Why are you locking to a single core for QueryPerformanceCounter? The whole reason you use QPC instead of RDTSC is so you don't have to lock it to a specific core. If there's a legit reason, you should probably just make a dumb thread for it and not much else since you don't want to rely on a specific core for your core game loop or something. Then just have a variable updated that the other threads read.

Unless Microsoft changed the specification for TimeGetTime, it is entirely inappropriate for a high-resolution time counter. It used to update only 64 times per second.

Share this post


Link to post
Share on other sites
 

 

> winapi QPC

 

Make sure to not mix nanoseconds/microseconds/etc. with milliseconds.

Also, there's no guarantee that each core will have the same value returned by QueryPerformanceCounter().

 

> I've rewritten my code as such but timeGetTime() - currentTime always seems to return zero.

 

Well, those two seems to be the same thing, the current time.

 

Also, did you make a multi-theaded main loop or are you creating a particular thread to execute just a brief code? If doing multi-thread, the usual is to make the main loop multi-threaded, and each thread has their own track of the time. Physics threads, for example, **usually** run with fixed delta time (16 milliseconds). It seems that you are doing the second, however, creating a thread in the middle of the main loop and mixing timers of both threads (?).

 

> So I would like to know the definitive answer as to how to do this properly on multicores.

 

There's on definitive answer. That pretty much depends how you are making your main loop (and how you are makin the thread, as I mentioned above).

 

Ok so you're saying not to use QPC, it seems there is no consensus. 

Of course I meant lastTime there.

I'm also not doing anything multithreaded yet, I mentioned that because as of now I only have 1 core masked and I would like to be able to let the app access all the cores.


Why are you locking to a single core for QueryPerformanceCounter? The whole reason you use QPC instead of RDTSC is so you don't have to lock it to a specific core. If there's a legit reason, you should probably just make a dumb thread for it and not much else since you don't want to rely on a specific core for your core game loop or something. Then just have a variable updated that the other threads read.

Unless Microsoft changed the specification for TimeGetTime, it is entirely inappropriate for a high-resolution time counter. It used to update only 64 times per second.

I was getting very weird results when last tried, it would spit out random numbers I guess as the cores switched under the code. Maybe as hodgeman said, they fixed it? I have to see. But I remember that I had to lock it to one thread back when I first wrote this code for it to work. I also don't really need high res time as of now, I'm simply using QPC for lack of options as nothing else works for me. 

Share this post


Link to post
Share on other sites

 

 

> winapi QPC

 

Make sure to not mix nanoseconds/microseconds/etc. with milliseconds.

Also, there's no guarantee that each core will have the same value returned by QueryPerformanceCounter().

 

> I've rewritten my code as such but timeGetTime() - currentTime always seems to return zero.

 

Well, those two seems to be the same thing, the current time.

 

Also, did you make a multi-theaded main loop or are you creating a particular thread to execute just a brief code? If doing multi-thread, the usual is to make the main loop multi-threaded, and each thread has their own track of the time. Physics threads, for example, **usually** run with fixed delta time (16 milliseconds). It seems that you are doing the second, however, creating a thread in the middle of the main loop and mixing timers of both threads (?).

 

> So I would like to know the definitive answer as to how to do this properly on multicores.

 

There's on definitive answer. That pretty much depends how you are making your main loop (and how you are makin the thread, as I mentioned above).

 

Ok so you're saying not to use QPC, it seems there is no consensus. 

Of course I meant lastTime there.

I'm also not doing anything multithreaded yet, I mentioned that because as of now I only have 1 core masked and I would like to be able to let the app access all the cores.

 

 

No, I mean you should use QPC, but it seems you are spawning a thread that has a brief life-time, I'm not sure (that's why I put that "?" there). While the usual approach is to create two (or more threads) that will start in the beginning of the program and end only when the application terminate.

Edit:

and possibly using a fixed time step for one of the threads.

Edited by felipefsdev

Share this post


Link to post
Share on other sites

Also, there's no guarantee that each core will have the same value returned by QueryPerformanceCounter().

This is just incorrect. If you are getting different values from different cores, it is a bug with the hardware timer being accessed (or more likely the BIOS code providing access to that hardware timer). If you do anticipate such bugs, I'd still use QPC or RDTSC locked to a core and publish that value for other threads.

Also, did you make a multi-theaded main loop or are you creating a particular thread to execute just a brief code? If doing multi-thread, the usual is to make the main loop multi-threaded, and each thread has their own track of the time. Physics threads, for example, **usually** run with fixed delta time (16 milliseconds). It seems that you are doing the second, however, creating a thread in the middle of the main loop and mixing timers of both threads (?).

They still would have the same problem since a single thread can and will change cores over time. And I advise against each thread having its own time. There is only disadvantages over publishing it from one thread (your highest resolution one) and having all others use that. You'd have sync issues since physics and animation and sound and everything else are all supposed to happen in a coordinated manner.

There's on definitive answer. That pretty much depends how you are making your main loop (and how you are makin the thread, as I mentioned above).

There is a definitive answer from Microsoft. If you're using Windows, they tell you the best practice is using QPC. While that doesn't mean you can't hit bugs, it does mean those bugs are more likely to get fixed since they are breaking the preferred solution.

(Edit) Minor clarification: I mention RDTSC, but only recommend it if you are locking on a specific core. And I don't particularly recommend doing that unless absolutely necessary (hint: it probably is not necessary!)

Share this post


Link to post
Share on other sites

> This is just incorrect. If you are getting different values from different cores, it is a bug with the hardware timer being accessed (or more likely the BIOS code providing access to that hardware timer). If you do anticipate such bugs, I'd still use QPC or RDTSC locked to a core and publish that value for other threads.

 

Huh, that's exactly the reason there's no guarantee they won't return the same value.

 

> They still would have the same problem since a single thread can and will change cores over time. And I advise against each thread having its own time. There is only disadvantages over publishing it from one thread (your highest resolution one) and having all others use that. You'd have sync issues since physics and animation and sound and everything else are all supposed to happen in a coordinated manner.

 

Using a different timer (like using a fixed time step for physics engine) is very common among engines (Unity, Godot, Unreal, for example).

 

> There is a definitive answer from Microsoft. If you're using Windows, they tell you the best practice is using QPC. While that doesn't mean you can't hit bugs, it does mean those bugs are more likely to get fixed since they are breaking the preferred solution.

 

I wasn't talking about using QPC or not using QPC, I was talking about how he's calculating the timer. And that synchronization will depend on how he's spawning the threads.

Edited by felipefsdev

Share this post


Link to post
Share on other sites

 

 

 

> winapi QPC

 

Make sure to not mix nanoseconds/microseconds/etc. with milliseconds.

Also, there's no guarantee that each core will have the same value returned by QueryPerformanceCounter().

 

> I've rewritten my code as such but timeGetTime() - currentTime always seems to return zero.

 

Well, those two seems to be the same thing, the current time.

 

Also, did you make a multi-theaded main loop or are you creating a particular thread to execute just a brief code? If doing multi-thread, the usual is to make the main loop multi-threaded, and each thread has their own track of the time. Physics threads, for example, **usually** run with fixed delta time (16 milliseconds). It seems that you are doing the second, however, creating a thread in the middle of the main loop and mixing timers of both threads (?).

 

> So I would like to know the definitive answer as to how to do this properly on multicores.

 

There's on definitive answer. That pretty much depends how you are making your main loop (and how you are makin the thread, as I mentioned above).

 

Ok so you're saying not to use QPC, it seems there is no consensus. 

Of course I meant lastTime there.

I'm also not doing anything multithreaded yet, I mentioned that because as of now I only have 1 core masked and I would like to be able to let the app access all the cores.

 

 

No, I mean you should use QPC, but it seems you are spawning a thread that has a brief life-time, I'm not sure (that's why I put that "?" there). While the usual approach is to create two (or more threads) that will start in the beginning of the program and end only when the application terminate.

Edit:

and possibly using a fixed time step for one of the threads.

 

No that can't be because I'm working in completely single threaded code, so I can't be spawning anything. I assumed you said that QPC can provide variable times from core to core so no don't use it?


 

Also, there's no guarantee that each core will have the same value returned by QueryPerformanceCounter().


This is just incorrect. If you are getting different values from different cores, it is a bug with the hardware timer being accessed (or more likely the BIOS code providing access to that hardware timer). If you do anticipate such bugs, I'd still use QPC or RDTSC locked to a core and publish that value for other threads.
 

Also, did you make a multi-theaded main loop or are you creating a particular thread to execute just a brief code? If doing multi-thread, the usual is to make the main loop multi-threaded, and each thread has their own track of the time. Physics threads, for example, **usually** run with fixed delta time (16 milliseconds). It seems that you are doing the second, however, creating a thread in the middle of the main loop and mixing timers of both threads (?).


They still would have the same problem since a single thread can and will change cores over time. And I advise against each thread having its own time. There is only disadvantages over publishing it from one thread (your highest resolution one) and having all others use that. You'd have sync issues since physics and animation and sound and everything else are all supposed to happen in a coordinated manner.
 

There's on definitive answer. That pretty much depends how you are making your main loop (and how you are makin the thread, as I mentioned above).


There is a definitive answer from Microsoft. If you're using Windows, they tell you the best practice is using QPC. While that doesn't mean you can't hit bugs, it does mean those bugs are more likely to get fixed since they are breaking the preferred solution.

 

But Windows has been pushing for QPC for commercial reasons not because it's the proper way. So i'm a little skeptical when reading into it. 

Share this post


Link to post
Share on other sites

> No that can't be because I'm working in completely single threaded code, so I can't be spawning anything. I assumed you said that QPC can provide variable times from core to core so no don't use it?

If you will use one thread for game logic and the other thread for physics, then don't use it for two threads. Just use it on one thread, and in the other you use a fixed time step.

 

How I do with my engine (edited for readbility):

static void threaded_update(void *data)
{
    cprogram *program = data;
    while (program->running) {
        if (/* Can run update? */) {
            program_update(program, get_delta());
        }
        if (/* should sleep? */) {
            do_sleep(program->update_thread_sleep_time);
        }
    }
}
 
static void threaded_physics(void *data)
{
    cprogram *program = data;
    while (program->running) {
        if (/* Can run physics? */) {
            program_update_physics(program, 1 / 60);
        }
        if (/* Should sleep? */) {
            do_sleep(program->physics_thread_sleep_time);
        }
    }
}
Edited by felipefsdev

Share this post


Link to post
Share on other sites

But Windows has been pushing for QPC for commercial reasons not because it's the proper way. So i'm a little skeptical when reading into it.


So Microsoft wants to tie people into their ecosystem with QPC. Why does it matter? The result is still any motherboard manufacturer (or whoever) with a bug in multicore access to QPC will feel immense pressure to fix it. You want that for any bugs in your code. Trust me. And we are far enough into multicore that I bet you will never see a major bug in this area again, unless Microsoft abandons their recommendation to use QPC.

If you aren't actively seeing an issue, just use QPC with certainty that it will work how it is supposed to work. If you happen to run into a bug down the road (doubtful), it's easy enough to patch the code by replacing QPC calls with calls to read a timer you publish from a thread that doesn't change cores. But honestly, that will never happen. This theoretical bug you're wasting time trying to avoid just doesn't exist today. Sure it existed in the first multicore systems. But unless you have a time machine, don't worry about it.

Share this post


Link to post
Share on other sites

> No that can't be because I'm working in completely single threaded code, so I can't be spawning anything. I assumed you said that QPC can provide variable times from core to core so no don't use it?

If you will use one thread for game logic and the other thread for physics, then don't use it for two threads. Just use it on one thread, and in the other you use a fixed time step.

I'm talking about right now, what should I use right now in single threaded code? Forget multi threading, I'm not even planning it, I just said it as an example.


 

But Windows has been pushing for QPC for commercial reasons not because it's the proper way. So i'm a little skeptical when reading into it.


So Microsoft wants to tie people into their ecosystem with QPC. Why does it matter? The result is still any motherboard manufacturer (or whoever) with a bug in multicore access to QPC will feel immense pressure to fix it. You want that for any bugs in your code. Trust me. And we are far enough into multicore that I bet you will never see a major bug in this area again, unless Microsoft abandons their recommendation to use QPC.

If you aren't actively seeing an issue, just use QPC with certainty that it will work how it is supposed to work. If you happen to run into a bug down the road (doubtful), it's easy enough to patch the code by replacing QPC calls with calls to read a timer you publish from a thread that doesn't change cores. But honestly, that will never happen. This theoretical bug you're wasting time trying to avoid just doesn't exist today. Sure it existed in the first multicore systems. But unless you have a time machine, don't worry about it.

 

Ok I'm going to try unlocking all my threads, and get back how it goes. And they're pushing it so that it gets implemented at hardware level. If they can get hardware to rely on winapi calls that'd be great for them.

Edited by VanillaSnake

Share this post


Link to post
Share on other sites

Yes, for single thread, use QPC. There's no problem with that.

 

Edit:

@richardurich, it's not a bug for QPC to return different values in different calls. It's the normal behavior, because it's the **current** peformance value. The thing is, delta-time is calculated in the beginning and end of a loop (everything OK with that), but if you call it on a different thread, it will obvisouly have a different value, because it's the **current** performance value at that moment. That's why using QPC on multiple threads requires non-trivial sync, and using a fixed time-step is simpler and efficient.

Edited by felipefsdev

Share this post


Link to post
Share on other sites

Yes, for single thread, use QPC. There's no problem with that.

 

Edit:

@richardurich, it's not a bug for QPC to return different values in different calls. It's the normal behavior, because it's the **current** peformance value. The thing is, delta-time is calculated in the beginning and end of a loop (everything OK with that), but if you call it on a different thread, it will obvisouly have a different value, because it's the **current** performance value at that moment. That's why using QPC on multiple threads requires non-trivial sync, and using a fixed time-step is simpler and efficient.

No it doesn't work. QPC is speeding up every time the window receives a message and slows down when it's got full focus. Is there anything useful anyone can contribute?

Share this post


Link to post
Share on other sites

Yes, for single thread, use QPC. There's no problem with that.

Edit:
@richardurich, it's not a bug for QPC to return different values in different calls. It's the normal behavior, because it's the **current** peformance value. The thing is, delta-time is calculated in the beginning and end of a loop (everything OK with that), but if you call it on a different thread, it will obvisouly have a different value, because it's the **current** performance value at that moment. That's why using QPC on multiple threads requires non-trivial sync, and using a fixed time-step is simpler and efficient.

No it doesn't work. QPC is speeding up every time the window receives a message and slows down when it's got full focus. Is there anything useful anyone can contribute?
Elaborate please. QPC does not change speeds. It's just an API call.

Feel free to ignore everything I said, and just go with what Hodgman said in the first response to your original post. It is the correct advice (although TSC doesn't need adjustment for dynamic clocks, just synchronization logic between cores that is provided by QPC).

Or google this stuff. You can find MSDN articles explaining why you should use QPC instead of RDTSC in multicore, why to use QPC instead of timeGetTime, etc.

Share this post


Link to post
Share on other sites

I mean unlocked QPC doesn't work. I removed the affinity mask and everything went haywire. My animation is playing faster now when I interact with the window by moving or clicking mouse, and when I stop sending the window messages the animation starts to stagger. I think that's a good indication that QPC is malfunctioning because of being asked from separate cores. So what should I do now?

Share this post


Link to post
Share on other sites

@VanillaSnake, since it doesn't work on single-threaded, I wonder if you are using QPC correctly. The function is used on SDL (I don't recall if it's the SDL1 or SDL2) and GLFW.

 

Do you use QPC like this:

long long get_milliseconds() {
  LARGE_INTEGER freq;
  QueryPerformanceFrequency(&freq);
  LARGE_INTEGER counter_now;
  QueryPerformanceCounter(&counter_now);
  return (1000LL * counter_now.QuadPart) / freq.QuadPart;
}

?

 

then you get delta time using:

starttime = get_milliseconds();
/* do stuff */
deltatime = get_milliseconds() - starttime; 
Edited by felipefsdev

Share this post


Link to post
Share on other sites

This is it:

LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
Timer.deltaTime = float(currentTime.QuadPart - Timer.lastTime.QuadPart) / Timer.frequency.QuadPart;

That's at frame start at frame end I call QPC(&Timer.lastTime).

Edited by VanillaSnake

Share this post


Link to post
Share on other sites

I mean unlocked QPC doesn't work. I removed the affinity mask and everything went haywire. My animation is playing faster now when I interact with the window by moving or clicking mouse, and when I stop sending the window messages the animation starts to stagger. I think that's a good indication that QPC is malfunctioning because of being asked from separate cores. So what should I do now?

Correlation does not mean causation. Did you confirm the program switched threads, and that switch aligned with your issues? Are you using RDTSC or anything derived from it?

Your issue is somewhere else, but I suspect you'd rather blame QPC than accept that fact. If QPC had the issues you seem to think it has, sfml would be breaking every single application that uses their clock. SDL would break anything using SDL_GetPerformanceCounter.

Believe me or don't. It's really your call at this point, and I think you've gotten all the help you can receive until you provide more details that reveal where the actual bug is.

That is what Microsoft tells you, but it's a lie. If you break in the debugger just before QPC is called and step into it, you will see that it is nothing but a simple call to RDTSC.

On systems with invariant TSC, yes. It's an optimized call in those situations. A quick google search shows CPUID.80000007H:EDX[8] is what indicates invariant TSC. But on older systems, QPC will absolutely be a far more expensive call. You can even google about complaints on its performance.

Share this post


Link to post
Share on other sites

 

I mean unlocked QPC doesn't work. I removed the affinity mask and everything went haywire. My animation is playing faster now when I interact with the window by moving or clicking mouse, and when I stop sending the window messages the animation starts to stagger. I think that's a good indication that QPC is malfunctioning because of being asked from separate cores. So what should I do now?


Correlation does not mean causation. Did you confirm the program switched threads, and that switch aligned with your issues? Are you using RDTSC or anything derived from it?

Your issue is somewhere else, but I suspect you'd rather blame QPC than accept that fact. If QPC had the issues you seem to think it has, sfml would be breaking every single application that uses their clock. SDL would break anything using SDL_GetPerformanceCounter.

Believe me or don't. It's really your call at this point, and I think you've gotten all the help you can receive until you provide more details that reveal where the actual bug is.

 

I will have to agree with @richardurich. Your QPC seems just fine. It's more likely the problem is in another part of your engine.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this