How to properly get delta time on modern hardware?

Started by
62 comments, last by Finalspace 7 years ago

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.

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

Advertisement

however I'm having to lock my cpu to a single core as a result

On a particular series of AMD cpu's in the early 2000's, there was a bug that caused QPC values per core to drift. There was a bugfix IIRC (microcode patch)? QPC works across cores AFAIK - Windows does any book-keeping required on dynamically clocked CPU's.

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

Millisecond accuracy is nowhere near good enough to avoid drifting away from real world time very quickly. This is bad advice in general.

> 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).

From what I remember using QPC unlocked the numbers were really random as the code jumped cores. So you're saying that it is the preferred method? And I can call from any core to get same exact timing now?

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

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.

> 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.

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

> 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.

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!)

> 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.

> 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.

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

This topic is closed to new replies.

Advertisement