Sleep based timer hack

This one gets asked alot, so I thought I’d post it seperately.

Attributions:
Contributed to the community by TheLorax.
This version from mbishop’s pacman clone.


// SleepTimer.java
// Here we have "thelorax"'s famous "sleep" timer.  This uses Thread.sleep()
// to get higher-resolution timing under Windows 9x platforms.
public class SleepTimer implements Runnable {

   // Number of elapsed ticks.  A tick is fired every time a sleep occurs.
   private int ticks;

   // The Thread that will be run.
   private Thread timerThread;

   // Our current delay and our desired delay.
   private long msDelay, targetMs;

   // Do we let this Thread correct itself?
   private boolean autoCorrection = true;

   // Is this Thread running?
   private boolean running = false;

   // Difference since last tick.
   private long timeDiff;

   // Desired frames per second.
   private int autoLength;

   // Start time and end time.
   private long startTime, endTime;

   // Of course we want a high priority to do our timing right.
   public SleepTimer() {
      timerThread = new Thread(this);
      timerThread.setPriority(Thread.MAX_PRIORITY);
      timerThread.setDaemon(true);
   }

   public int getTickCount() {
      return ticks;
   }

   // I added this so I could see the number of ticks missed
   // on a per-second basis.
   public void resetTickCount() {
      ticks = 0;
   }

   public void startTimer() {
      running = true;
      timerThread.start();
   }

   public void stopTimer() {
      running = false;
      try {
         timerThread.join();
      }
      catch (Exception e) {}
   }

   // We set auto-correction with a desired frames (ticks) per second.
   public void setAutoCorrection(boolean on, int sampleLength) {
      autoCorrection = on;
      autoLength = sampleLength;
   }

   public void setDelay(int tmsDelay) {
      msDelay = tmsDelay;
      targetMs = msDelay;
   }

   // Sleeps the specified amount, lets other Threads know, then
   // corrects itself if auto-correcting is set.
   public void run() {
      startTime = System.currentTimeMillis();
      try {
         while (running) {
            Thread.sleep(msDelay);
            ticks++;

            synchronized(this) {
               notifyAll();
            }
            if (autoCorrection && (ticks % autoLength == 0)) {
               endTime = System.currentTimeMillis();
               timeDiff = ((endTime - startTime) / autoLength) - targetMs;
               startTime = endTime;
               if (timeDiff > 0) {
                  msDelay--;
               }
               if (timeDiff < 0) {
                  msDelay++;
               }
            }
         }
      }
      catch (Exception e) {
         System.err.println("Exception in Timer Thread.");
         e.printStackTrace();
      }
   }
}

Thanks Jeff. I had not wanted to post it until giving TheLorax a chance to do so, but you beat me to the punch. :slight_smile:

Yeah, i had to thin kthis one through carefully as I’m very dilligent about author’s rights, beign one myself.

Since Lorax has it publically posted in the archives though, and mbishop had already posted a link to his source, I assumed an implicit permission to repost. (If I was wrong guys, tell Chris to remove it and hit me with a wet tuna :slight_smile: )

Thanks for digging it out and posting it. I was a bit leery about doing it myself, but he did post it and I did give him credit in the code… :slight_smile:

Michael Bishop

I have been trying to understand how this timer hack works, but it seems to be that I get randomly error in timerthread where time out value is negative. I have figured out that his has something to do with too small autoCorrection values. The picture thread just freezes.

I’ve also found out that with this “hack” i see slowdowns after a period of time and it is repetitive.

Can someone please lighten me up on the use of this thing before I implement it into my game. Otherwise it seems to be really great, except for those two little faults on my side.

I’m also kind of confused with this 1.4 fullscreen rendering because of the lack of paint and update methods in away. I guess it just time to get used to it. Does anyone have any article where I could review the basic principles of fullscreen animation? It seems like a lot of the AWT rules are now old and almost useless.

This is all the code I used to get it running at “fps” fps.

frameTimer = new SleepTimer();
frameTimer.setDelay(1000 / fps);
frameTimer.setAutoCorrection(true, fps);
frameTimer.startTimer();

I’ve never had it throw an error before. Then again, I haven’t run it over 60 frames-per-second.

Michael Bishop

Hmm… that makes me wonder what is wrong with my code then…

The animation is smooth for certain amount of time and then it kind of ticks. Then it starts over again. I guess I have to start looking through the render loop to see if I can find any nasty code from there.

That sounds suspiciously like garbage collection without seeing any code. Definitely avoid creating objects in your render loop and run it against a profiler.

Michael Bishop

The only object I’m creating is the graphics object. I guess I have to figure out a way to create it outside, but would this really affect? I mean its very simple a aquare moving across the screen and the player rotates around its origin according to mouse and then a moves whatever direction the player decides.

Could the affinetransform be the reason? Now its making the pictures on the roll, but should I make and array of transfromation where the correct transformation gets called each and every time?

The memory usage would be a lot greater, because for smooth animation it would have to be like 70 images or so. 360/5. And then I would have to forget affinetransfroms.

It can’t be the graphics 2d object can it? So many other programs create it at the beginning of rendering loop so I highly doubt so.

Hmm I still get the negative timeout error at java native code. Perhaps my garbage collection is wrong and this is really messing up the system. The animation runs really great for the time it twiches. Then after a while the screen freezes dues the negative timeout error.

Edited to say:

It’s the mouse rotating the player which causes the problem. Because of the player direction has to be updated all the time, the animation twiches at some point. I will find out why.

[quote]I
I’m also kind of confused with this 1.4 fullscreen rendering because of the lack of paint and update methods in away. I guess it just time to get used to it. Does anyone have any article where I could review the basic principles of fullscreen animation? It seems like a lot of the AWT rules are now old and almost useless.
[/quote]
Yep you are going around the entire AWT paint mechanism when you do Buffer Flipping (and for darn good reasons, you need more control and more efficiency then AWT gives yo uto do cutting edge games.)

Im not sure hwo much there is to explain but Ill do so in the BufferFlipping thread…

How is this timer used?
Every time I set this up and call wait() on my main thread,
nothing happens (I get no notifyAll()'s).

Can someone post a sample main() method that sets this
timer up and waits for it to notify it so I can paint?

Thanks ???

This could be a stupid idea, but maybe javax.sound.sampled could be misused to mimic a high(-er) resolution timer?
I was thinking about setting up a dataline and fill the buffer with exactly the amount of samples that would last one frame and then wait for the buffer to empty before going to the next frame.

I haven’t got around to try it yet, but I think it could work in theory, although there could be some performance loss.

Just a thought…

:slight_smile: Erik

[quote]Hmm I still get the negative timeout error at java native code. Perhaps my garbage collection is wrong and this is really messing up the system. The animation runs really great for the time it twiches. Then after a while the screen freezes dues the negative timeout error.
[/quote]
Ok, I’m here… ( dropped off the planet for a while, glad to see my work still floating round ).

The exception is because you might be timing something much smaller than I had expected and the “correction” value starts to occalate and then the sleep(x) drops to -something. I could probably fix it by only taking a percentage or some sort of logorithmic like function so the closer you get to zero the less it actually reduces the value by.

Hmmm… minimally it should probably throw a runtime exception if the sleep value drop to below zero.

[quote]This could be a stupid idea, but maybe javax.sound.sampled could be misused to mimic a high(-er) resolution timer?
I was thinking about setting up a dataline and fill the buffer with exactly the amount of samples that would last one frame and then wait for the buffer to empty before going to the next frame.

I haven’t got around to try it yet, but I think it could work in theory, although there could be some performance loss.

Just a thought…

:slight_smile: Erik
[/quote]
Just to short circuit that idea, it doesn’t work. I tried it out, but soon found out that databuffers are very finiky.

They appear only to work in chucnks that don’t translate into java very well. It works great for streaming, but your “resolution” is copletley dependat on the native “chunk” size normally something like 8192k ( 44.1k 16 bit stereo ) would equal a maximum timer resolution of 21 times/second… ugh.

If you think you can use the get availible ( or whatever it’s called ) that only works on chunks too, it’s hopeless. Since it’s non-blocking up to the point where it runs out of space and blocking after that you can’t even depend on it to take a specific ammount of time to add a specific number of samples.

The only ACCURATE timer availible is the J3d one, but even there you cannot even depend on an accurate resolution value since under lunix the value is screwed up and need to be caluculated dynamicaly.

Oyh…

You might think sun does not want us to succeed.

[quote]Just to short circuit that idea, it doesn’t work. I tried it out, but soon found out that databuffers are very finiky
[/quote]
Yes you’re right it doesn’t work, just tried it yesterday night :frowning:
Thanks for the explanation, though. It does clarify some things…

I heard (but I can’t confirm it) that the above solution where the timer runs in a seperate thread doesn’t work well on linux and/or unix. Don’t know if that’s true (can someone confirm it?), but I have a solution which slows down a (‘main’) thread which seems to work well (at least on windows systems but I heard on other platforms too). Complete with (automatic) frameskip option. If someone’s interested, I can post it.

Greetings,
Erik

As I mentioned on the old board, there is the chance the new Linux Kernal (sorry Kernel!) might fix the thread problem.

High performance threading turns up in version 2.6 (or version 3.0 if they decide to change the name) and here is a bit of an article for your interest:
http://www.onlamp.com/pub/a/onlamp/2002/11/07/linux_threads.html

Anybody been able to try it with Java yet?? (Not even sure if it’s available yet.) http://www.kernel.org/ does not seem to have it.

Utterly disapointed with the sound syncing system, it may be that it works fine on some JVM’s though, as I never tried it with IBM’s JVM.http://www-106.ibm.com/developerworks/java/.

At the end of the day the only system that works reliably (when given 100% cpu) is running unlimited, which is what I use as a fall back method.

But this means using Doubles/Floats/1.15.16 fixed point for all your counters, co-ords etc which can look messy because this means you have to deal with 1.5 pixels of travel rather than just whole integers.

Threads can behave very wierdly, if you sync on one they are typically stable (±5% variation), if you don’t sync on them (say your frame rate drops below 60Hz) then expect the Thread to become unstable (-15% so 60Hz drops to 51Hz).

This really annoys me as ALL IBM compatable PC’s (from the very first 64K tape machine upwards) have a 8253 timer chip in (PC speaker) which gets a 1,193,180Hz signal from the PC’s oscilator (8284 I believe). And can be read (albeit as a 16 bit counter, but that is not difficult to get round).

Want to know how many bytes this code takes?


I8_Ctrl_Port     EQU 043h
I8_T2_Port       EQU 042h

  mov  al,04h
  out  I8_Ctrl_Port,al

  in   al,I8_T2_Port  ;Get Low Byte Of Counter.
  rol  ax,8
  in   al,I8_T2_Port  ;Get High Byte Of Counter.
  rol  ax,8


[b]Can even be done in Turbo Pascal![/b]

  Port[ $43 ] := $04;
  Read_Timer :=( Port[$42] SHL 8 )+ Port[ $42 ];


Thats about 14 bytes that execute in under 30 clock cycles ( Port IO is still very slow). And do they use it? Do they hell…

What you need to be thinking about is where are the hi-res timers located within a PC, most of them are off limits because of Java, but there must be a way to access the high res timer in the network card.

I’m sure the TCP/IP packets get date stamped, what if you could route out a packet that was received imediately and read the time fields (but I don’t think this is accessable in Java). But interestingly you can set/catch a timeout value (unstated accuracy - could be minutes!).

Have not had the time to try it yet, anybody want to have a go?

ServerSocket.SetSoTimeout( int ); Looks interesting, available in JDK1.1 too.

public void setSoTimeout(int timeout) throws SocketException

Or some variation on this? Probably causes a security exception in Applets through…

All the best,

Woz.

i tried a lot to get a stable fps, but nothing works, the System.currentTimeMillis is so unaccurat.

Instead i use a seperate TimerThread class with a run method like this

  public void run()
{
    System.out.println("> timer thread started " + getPriority());

    isRunning = true;
    
    while ( isRunning )
    {
        try
        {
            Thread.sleep(1);
        }
        catch ( Exception ex )
        {
        }

        synchronized ( itsMutex )
        {
            itsTickCount++;
        }
        MainFrame.itsMainFrame.timerTick(itsTickCount);
    }
}

this thread runs at max priority

/**********************************************************************************************
 * setTickCount
 *********************************************************************************************/
  public void setTickCount(long ticks)
{
    itsTickCount = ticks;
}

/**********************************************************************************************
 * getTickCount
 *********************************************************************************************/
  public long getTickCount()
{
    long value = 0;
    
    synchronized ( itsMutex )
    {
        value = itsTickCount;
    }

    return value;
}

use this as selectors and voila, at a fps of 90 my calculated framerate is 90.0

hope it helps