New Timer Code

Hey all, the org.lwjgl.Sys class now has a radically redesigned hires timer.

On Speedstep, HyperThreaded, or dual-processor systems, the hires timer reports wildly inaccurate values (you can check this yourself using System.nanoTime()). Unfortunately this renders every single game I’ve got on my speedstepped hyperthreaded laptop totally unplayable - even my own games, which I’ve had to develop with the problem! HalfLife 2 sucked greatly because of this as well.

The symptom manifests itself as the game suddenly going into treacle 30fps mode for a few seconds, then speeding back up to normal rate, over and over. It’s horrible.

Sometimes you can start out at normal speed but then the game speeds up instead.

The new hires timer continually corrects itself to take account of this phenomenon. It’s not 100% perfect (it can’t ever be 100% perfect because it basically has to make a guess that something’s wrong 2-3 frames after the slowdown begins) but I can finally play Puppytron at a creamy smooth 60fps on my own computer. And Valve with their multi-million dollar budgets don’t appear to be any the wiser :slight_smile:

Just thought I’d let you know.

Cas :slight_smile:

FYI, the “correct” thing to do is to set the processor affinity so that the timer values don’t jump around. It’s not a guarantee, but it does usually prevent the issue.

EDIT: BTW, did you ever get your AMD64 machine?

there is a bug opened at Sun for System.nanoTime() ? what a workaround …

Affinity doesn’t help (tried it as well, just to prove this), and you can’t do this from Java anyway, and what’s more of course it means you lose a whole core which might otherwise have been used for something more useful.

This is not a “bug” in nanoTime, it’s a bug in just about all the timer code you’re ever likely to see. Every single game on this laptop runs badly as a result of this issue.

Jerason - seeing as the LWJGL code is BSD licensed it might well be good for you to have a look at what I’ve done and incorporate it in GAGETimer, which of course suffers from the same problem.

Cas :slight_smile:

Further update:
I’ve removed the timer calibration code, and ditched the hires timer completely from LWJGL win32. Now we are using a timer which is accurate to 1ms, which is accurate enough for most purposes (and is also, coincidentally, how accurate the Linux and MacOS timers are too).

Cas :slight_smile:

Awwww… :frowning:

Now we are using a timer which is accurate to 1ms, which is
accurate enough for most purposes

Framecapping needs more than that. Eg 1000/60… 16.666 etc msec. 17msec is 58.8fps and 16msec is 62.5fps. :-/

Please put it back in. The other one can stay there as alternative timer if you like.

I will enable the QPC timer if a special system property is set. Otherwise 1ms is pretty much accurate enough for more-or-less consistent framerates on all 3 OSes.

Cas :slight_smile:

Thanks :slight_smile:

Just remember that if you use it you’ll break your code on my laptop :slight_smile:

Cas :slight_smile:

Any chance of being able to choose the QPC timer per default but fall back if the computer it’s running on won’t be able to use it?

And is there no such thing as a QPC timer available on mac and linux, or is it just not implemented in LWJGL? I would be surprised if a mac didn’t have any high resolution timer…

I’m very wary of enabling QPC by default as it is definitely broken and the problem is going to get worse and worse as more HT/Speedstepped systems are deployed. I would rather use the 1ms timer by default and then we’re at parity with the Mac / Linux implementations as well.

Cas :slight_smile:

I found the following in an NVIDIA newsletter tip:

[quote]Don’t use the Read Time Stamp Counter (RDTSC) to do timing in your app. Here’s why: it is unusable on mobile platforms because calculations assume a fixed clock speed. Mobile platforms (such as notebooks) will throttle back the CPU at unexpected times making the tick count from RDTSC useless. Instead use QueryPerformanceCounter, which insures consistent architecture independent results.
[/quote]

[quote]I found the following in an NVIDIA newsletter tip:

Don’t use the Read Time Stamp Counter (RDTSC) to do timing in your app. Here’s why: it is unusable on mobile platforms because calculations assume a fixed clock speed. Mobile platforms (such as notebooks) will throttle back the CPU at unexpected times making the tick count from RDTSC useless. Instead use QueryPerformanceCounter, which insures consistent architecture independent results.
[/quote]
I think the problem is that QPC falls back on RDTSC on some hyperthreaded system. Thus makeing QPC just as useless as RDTSC.

Could we have both QPC and the new timer in lwjgl at the same time. Just document the differnces and potential problems.

cas: Have you mesured the frequency that you get with QPC on the laptop with the one you get on working computers. If it falls back on RDTSC the freq will be much higher than usuall. Could it be possible to detect a potential problem?

FYI, QueryPerformanceCounter is what the GAGE DLL uses. The problem is that it screws up on multiprocessor systems unless the affinity is set.

Hyperthreading is definitely a cool technology, but I’ve seen quite a few programs screw up and die on it. For example, a Java program I wrote ends up in a race condition when it loads information on startup. Bad, bad, bad. It’s going to take some work to figure out how to properly deal with HyperThreaded systems. :-/

The solution is simple: use timeGetTime instead :slight_smile: It’s not as hi-res but who cares, it’s consistent and it’s more or less all we need!

Cas :slight_smile: