🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Should timers in an engine be on separate threads?

Started by
13 comments, last by ROGRat 5 years, 8 months ago
2 hours ago, Hodgman said:

IMHO, the primary purpose of OS threads is to allow you to run code on more that one CPU core, which is something that you want to do when you've got code that's extremely computationally intensive.

Waiting for a certain amount of time to elapse is about the least computationally intensive thing you can do, so you shouldn't use threads to solve that problem.

Games are also a little different to typical software, in that we typically have a "game loop" that's running at real-time rates, e.g. 30Hz. The most typical solution for timers in games is to simply poll them once per frame. i.e. for each timer, in the main game loop (once per frame), check if the timer has elapsed and run the associated event if so.

This is true on a small number of buggy AMD CPUs from the early 2000's, if they don't have the appropriate patches installed, if they use certain power saving settings, if you're still running on Windows XP or Windows Server 2003.

It's pretty safe to assume that QPC just works on modern Windows. These days, it will automatically select a different implementation that just works, depending on your hardware.

[edit] actually after posting, i re-researched this and found that Intel shipped some CPUs with this same bug as recently as 2014 and Win10 was observed actually selecting the buggy implementation... :(

I wish it was a problem that was confined to a handful of old processors that you rarely see in the wild anymore.  On some systems the problem is in the BIOS and keep in mind that the vast majority of users never update their BIOS.  The problem is made worse by the fact that most mainboard and system vendors do not provide an automated update path for it.

Implementing a timer using the method I suggested (on Windows) not only ensures an accurate timer across a broad range of systems, it also minimises scalability problems down the track.  If your application/game has multiple threads on multiple cores and needs to call QueryPerformance from   those threads, the resulting performance hit from doing so compared to calling it from a single dedicated thread is too high to ignore.

The so-called cost and complexity of threads, aside from being negligible in this context, is something that needs to be confronted and accepted in the era of many-core processors.  In this case, the small investment of time  and effort goes a long way. ?

Edit/Note: For C#/.Net Framework, call Stopwatch.GetTimestamp. It calls QueryPerformanceCounter internally.  Do NOT use DateTime.Now or Environment.TickCount.

Advertisement
12 minutes ago, ROGRat said:

The so-called cost and complexity of threads, aside from being negligible in this context, is something that needs to be confronted and accepted in the era of many-core processors.  In this case, the small investment of time  and effort goes a long way.

If you're talking about using a thread for the timer, to avoid this specific QueryPerformanceTimer bug, while keeping the rest of the program single-threaded, then yes, the additional complexity due to threads is basically negligible - but doing this so is also completely pointless, because you could just set the thread affinity of the main thread instead and get the same benefit for less complexity.

And, yes, every programmer is going to have to eventually make the jump to multi-threading if they're serious about performance.  Nothing about the OP's post indicates to me that they are ready to make that leap, but I could be mistaken.

Using threads for timers makes no sense imho, Order them on end-time, and there is at most one moment in time you're waiting for at any time. Fold timer handling in the game loop; communicating across thread boundaries is hairy enough, if you want something accurate in timing as well, problems only get bigger.

 

1 hour ago, a light breeze said:

If you're talking about using a thread for the timer, to avoid this specific QueryPerformanceTimer bug, while keeping the rest of the program single-threaded, then yes, the additional complexity due to threads is basically negligible - but doing this so is also completely pointless, because you could just set the thread affinity of the main thread instead and get the same benefit for less complexity.

And, yes, every programmer is going to have to eventually make the jump to multi-threading if they're serious about performance.  Nothing about the OP's post indicates to me that they are ready to make that leap, but I could be mistaken.

It’s not pointless at all.  Assigning your main thread to a single core, just to sidestep threading, is not just a code smell, it’s a train wreck.

If another process comes along and does the same thing, and uses more CPU time than your application can tolerate, it will either perform poorly or stop responding entirely. Until that other process starts behaving. If ever.

If the same thing happened with my implementation, even if two processes came along and specifically targeted the core my main thread was running on and the core my timer was running on, not only would my application continue to run (since it’s free to be scheduled on another, less utilised, core) but my timer almost certainly would too. :+D

This topic is closed to new replies.

Advertisement