Bug 639 : Sketches lock up when system time is set back
Last modified: 2008-08-13 20:35



Assigned To:

Attachment Type Created Size Actions

Description:   Opened: 2007-10-11 16:26
Processing revision: 0126
Operating system: Windows XP

Processing uses the difference between the current time and the time the
last frame was drawn in order to figure out how long to sleep (in order to
maintain the desired framerate). It uses System.currentTimeMillis() but
unfortunately this is tied to the system time. If the system time is
rolled backwards between frames then Processing will calculate a large nap
time (I think) and the sketch will lock up until the clock catches up with
the time before it was rolled backward. To test this, load any looping
sketch and set the system clock back one minute. The sketch will lock up
for one minute.

This is more than just a minor annoyance on some systems with SpeedStep
(and possibly Cool'n'Quiet). The constant processor speed ramping can
cause the clock to drift forwards. Windows will eventually notice this and
reset the clock backwards to the correct time and this locks up the sketch
for several minutes.

I believe that using System.nanoTime() would correct this since it is not
tied to the system clock and is intended specifically for measuring
intervals like this. Unfortunately it is available only in Java 1.5 or
later. If there is some way to dynamically use it only if available, that
could be an option. I'm not a Java guy but I'm hoping there is some way to
do this.

For people using Java 1.4, I believe there is a workaround to limit the
effects of the problem. The nap time shouldn't ever legitimately be larger
than the time between frames (ie, 1000 / frameRateTarget). So merely
clamping it to the proper range should keep the sketch running. It will
still have a slight hitch when the clock rolls back but otherwise will keep
working. I would propose changing the current frame rate limiting code to
something like this:

long frameTime = (long)(1000.0f / frameRateTarget);
long now = System.currentTimeMillis();
nap = (int) (frameRateLastDelayTime + frameTime - now);
if (nap > frameTime)
// clock went backwards
nap = frameTime;
else if (nap < 0)
// can't keep up with frameRateTarget, draw next frame ASAP
nap = 0;
frameRateLastDelayTime = now + nap;

If this could be combined with the dynamic use of System.nanoTime(), it
would provide the best of both worlds: no problems on Java 1.5 and only a
minor hitch on Java 1.4.
Additional Comment #1 From fry 2007-10-12 06:05
as of earlier this week, we've decided to drop support for versions of Java
prior to 1.4, and this is one of the reasons--that we can't do timing
properly w/o the APIs in 1.4 (and improved in 1.5).

so a change will be coming as the threading model is reworked based on the
new 1.4 stuff.
Additional Comment #2 From fry 2007-10-12 06:07

*** This bug has been marked as a duplicate of 511 ***
Additional Comment #3 From fry 2008-08-13 20:35
We've moved to Java 1.5 as a minimum requirement, and are using
System.nanoTime() internally as of release 0145 (to arrive this week,
currently in SVN).