Thread.sleep accuracy?

I’m new to game development with Java and I’ve noticed some odd behavior with Thread.sleep.

It seems that the accuracy of Thread.sleep is suspect. Take the following code as an example…


public class ClockTest
{
   public static void main(String[] args)
   {
      for (int i = 1; i <= 20; i++)
      {
         // Using absolute clock time
         long start = System.currentTimeMillis();
         try
         {
            // Sleeping for 5 milliseconds
            Thread.sleep(5);
         }
         catch (InterruptedException e)
         {
            e.printStackTrace();
            System.exit(1);
         }
         long end = System.currentTimeMillis();
         
         // Output results *after* the time captures to reduce extraneous code's execution time
         System.out.println("Attempt " + i + ": " + (end - start) + " millsecs");
      }
   }
}

…which produces…

Attempt 1: 6 millsecs
Attempt 2: 6 millsecs
Attempt 3: 5 millsecs
Attempt 4: 5 millsecs
Attempt 5: 5 millsecs
Attempt 6: 5 millsecs
Attempt 7: 5 millsecs
Attempt 8: 5 millsecs
Attempt 9: 5 millsecs
Attempt 10: 5 millsecs
Attempt 11: 21 millsecs <-- ouch
Attempt 12: 5 millsecs
Attempt 13: 5 millsecs
Attempt 14: 5 millsecs
Attempt 15: 5 millsecs
Attempt 16: 5 millsecs
Attempt 17: 6 millsecs
Attempt 18: 5 millsecs
Attempt 19: 5 millsecs
Attempt 20: 5 millsecs

I’m using the 1.6.0_01 JDK under Linux (Intel single core CPU). As you can see, sometimes, Thread.sleep can take over 4x the amount of time requested. Most of the time, it seems that it can handle a 5 millisecond request time, and so it’s not that the OS time facilities that the JVM uses can’t handle that small of a resolution. It would seem that other factors are involved… maybe JVM native threads (e.g for garbage collection)Huh

Can anyone explain the difference in the numbers? Also, how do you release CPU time to other threads (e.g. the AWT thread) while still being able to keep a constant frame rate if Thread.sleep durations are not consistent?


you might increase this by using new Threads instances with MAX_PRIORITY set up. But Java does get slower and slower, as time runs… :-\

Thread.sleep specifies a minimum time to sleep for, not a maximum.If another thread kicks in (like the garbage collector, or even another non-java process) then your thread may remain sleeping for longer than you specified. This is standard threading behaviour for most OS threading models, regardless of the language they’re written in.

If you want to sleep for a specific amount of time (eg. locking your game to a steady framerate) then you’ll probably be better off calling sleep(0) in a loop until the required time has elapsed. It’s usually a bad idea to start messing with MAX_PRIORITY threads, as you can suck up all the cpu time and leave other systems starved.

Orangy, I tried your suggestion but I’m still not getting the constant timing delay that I would need, for example, for a game or rendering loop. I even switched from a 5 to a 10 millisecond delay. (broumbroum, I also tried setting the main thread to the max priority without good results either.)

My system resources utilization is very very low: CPU, memory, disk I/O all very low usage. I don’t know what the kernel scheduler time slice per process is, don’t know what the Java scheduler time slice is per thread (using the Sun HotSpot JVM), and haven’t turned on GC logging to know what GC activity is happening — but I’m assuming that a steady 10 millisecond delay rate should be achievable. With a 10 millisecond slice of time, the game loop would proceed at 100 cycles per second, which sounds like a reasonable number.

If the problem is really the OS process scheduler or the JVM thread scheduler (e.g. with time it’s giving to the GC native thread), how are other Java games achieving any kind of constant frame rate? Are their threads using Thread.sleep at all?


public class ClockTest 
{
	public static void main(String[] args)
	{
		for (int i = 1; i <= 20; i++)
		{
			// Using absolute clock time
			long start = System.currentTimeMillis(); 
			long delay = start + 10; // 10 millisecond delay
			try
			{
				// Sleeping for 0 milliseconds
				Thread.sleep(0);
				while (System.currentTimeMillis() < delay);
			}
			catch (InterruptedException e)
			{
				e.printStackTrace();
				System.exit(1);;
			}
			long end = System.currentTimeMillis();
			
			// Output results *after* the time captures to reduce extraneous code's CPU cycles
			System.out.println("Attempt " + i + ": " + (end - start) + " millsecs");
		}
	}
}

Results:
Attempt 1: 10 millsecs
Attempt 2: 13 millsecs
Attempt 3: 10 millsecs
Attempt 4: 10 millsecs
Attempt 5: 10 millsecs
Attempt 6: 11 millsecs
Attempt 7: 10 millsecs
Attempt 8: 10 millsecs
Attempt 9: 10 millsecs
Attempt 10: 10 millsecs
Attempt 11: 20 millsecs
Attempt 12: 10 millsecs
Attempt 13: 10 millsecs
Attempt 14: 10 millsecs
Attempt 15: 10 millsecs
Attempt 16: 10 millsecs
Attempt 17: 10 millsecs
Attempt 18: 10 millsecs
Attempt 19: 10 millsecs
Attempt 20: 10 millsecs

Hi,

This seems to be a common problem for people trying to do fixed-frame rate games. One technique I’ve seen used by CaptainJester and KevGlass is to use Thread.yield() in a loop until System.nanoTime() returns the correct time that you’re waiting for. Search for any code by them on these forums to see that in action - Kev Glass uses it in his Phys2D code in the World class.

However this technique does use all the CPU (even though it still gives other threads a chance because of Thread.yield()).

Why do you need to sleep for a fixed time? In my games I don’t use a fixed time step between frames, I just update each frame according to how much time elapsed since the last frame, and after painting I sleep for 1 millisecond to let other threads have a go. :slight_smile:

Best regards,
Keith

this is just my own opinion, but I think this is the method everybody should use, I mean this way is the best one, there is no need of fixed FPS and for example if your computer hang for a moment it will involve problem even if your programming method produce perfect FPS or on slow computer you will have problem. the best is to use elapsed time to update all your game component this way you will always produce a good result… even if you put your computer in “sleep mode” and power it after an hour :wink:

We get fixed frame rates by using sleep(0) in a tight loop watching a hi-res timer. It’s easily accurate enough, especially with vsync turned on :wink: Yield() tends to use the CPU unnecessarily; sleep(0) makes it look idle.

Cas :slight_smile:

Your problem might simply be using System.currentTimeMillies() to measure the results, since this is known for being inaccurate (unless something changed in recent JDK versions). Try System.nanoTime() instead.

Fixed framerate vs. variable framerate is an entirely different discussion that we’ve done to death several times on these forums, so lets not derail this discussion with yet another restatement of that argument. Suffice to say that both methods have their advantages and disadvantages.

Back on topic, I’m going to agree with cylab that System.currentTimeMillis is what’s causing your problems here. IIRC it only has a 10ms accuracy on Windows 2000 and XP.

Also keep in mind Thread.sleep() is going to act different depending on the OS.

On Windows I got pretty good results by using Thread.sleep(1) in a loop until the time occurs, although it requires this trick: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6435126
This is similar to other methods posted here, but doesn’t take up a lot of CPU.

Mac OS X seems to be pretty accurate with Thread.sleep().

Either way, don’t expect a fixed frame rate based on Thread.sleep() to be full-proof - expect variable frame rates in some situations.

I’m using Linux (kernel 2.6.2.2) and I thought I read that the timer that Thread.sleep uses has a 1 millisecond resolution time on that platform.

However, I took Thread.sleep out of the equation completely, and I’m still not getting constant results, which leads me to believe that unless others can reproduce these numbers that it must be something specific to the OS or the JRE and System.nanoTime/System.currentTimeMillis call on this platform that’s problematic.


public class ClockTest 
{
	public static void main(String[] args)
	{
		for (int i = 1; i <= 20; i++)
		{
			// Using relative clock time
			long start = System.nanoTime(); 
			
			// 10 millisecond delay in nanoseconds
			long delay = start + 10000000; 
			
			while (System.nanoTime() < delay);
			
			long end = System.nanoTime();
			
			// Output results *after* the time captures to reduce extraneous code's CPU cycles
			System.out.println("Attempt " + i + ": " + ((end - start) / 1000000) + " millsecs");
		}
	}
}

Attempt 1: 10 millsecs
Attempt 2: 10 millsecs
Attempt 3: 10 millsecs
Attempt 4: 10 millsecs
Attempt 5: 10 millsecs
Attempt 6: 17 millsecs
Attempt 7: 10 millsecs
Attempt 8: 10 millsecs
Attempt 9: 10 millsecs
Attempt 10: 10 millsecs
Attempt 11: 17 millsecs
Attempt 12: 10 millsecs
Attempt 13: 10 millsecs
Attempt 14: 10 millsecs
Attempt 15: 10 millsecs
Attempt 16: 16 millsecs
Attempt 17: 10 millsecs
Attempt 18: 10 millsecs
Attempt 19: 10 millsecs
Attempt 20: 10 millsecs

The JIT might be kicking in… compiling the very method you’re benchmarking.

Let the program run for a minute, and check whether it eventually stabilizes.

oki

I always notice 16/17ms on my computers, maybe it could be different depending on CPU.

this benchmark code seems not really accurate, you instanciate about two/three new String object each iteration (may produce GC) also you produce output to the console in your main loop (could be very long sometime), also as said by riven jit could be still working as there is not a lot of loop in your bench and no warmup.

i would recommend you something like that

public class ClockTest 
{
static long times[1000];
	public static void main(String[] args)
	{
                        bench(); //prevent JIT and make a little warmup
                        Thread.sleep(5000); //wait for system stability
                        bench();
                        //there output times array to see results
                
                     }

                    static void bench()
                    {
                                      for (int i = 0; i < times.length; i++)
		{
			// Using relative clock time
			long start = System.nanoTime(); 
			
			// 10 millisecond delay in nanoseconds
			long delay = start + 10000000; 
			
                                                               //little more accurate
			long end = 0;                                                                
                                                               do
                                                               {
                                                                   end = System.nanoTime();
                                                               }
		                    while (end < delay);

			times[i]=end-startTime;
		}
                         }

}

[quote]Yield() tends to use the CPU unnecessarily; sleep(0) makes it look idle
[/quote]
hey, that’s a really interisting information, does that works for all platform ??

EDIT:
first sorry Orangy Tang ;-), but

[quote]We get fixed frame rates by using sleep(0) in a tight loop watching a hi-res timer. It’s easily accurate enough, especially with vsync turned on
[/quote]
does your games couldn’t be easier for people playing on slow computer unable to match your request FPS ? also vsync on will get screen refresh rate so it will depend uppon computer usually : 60,75,85,100 Mhz ?

also fo Orangy Tang :

[quote]I’m new to game development with Java and I’ve noticed some odd behavior with Thread.sleep.
[/quote]
I think that’s good to know about both method even if it is not the name of this thread…

Works on all platforms. We always change screen refresh rate to 60Hz if it’s available and turn vsync on; if we can’t get 60Hz, or vsync is definitely off, the timing is as accurate as we can get it using org.lwjgl.Sys.getTime() and Thread.sleep(0). We use the timer regardless of whether we think we’ve got vsync and 60Hz. Occasionally we drop a few frames when some other thing happens that slows the game down or we’re drawing just a bit too much for a crappy video card; big deal :slight_smile: 99% of systems work smooth and perfect 99.9% of the time using the method we’ve stuck with since 2003.

Cas :slight_smile:

http://www.java-gaming.org/forums/index.php?topic=10199.0
http://www.java-gaming.org/forums/index.php?topic=1494.0
http://www.java-gaming.org/forums/index.php?topic=13469.30
http://www.java-gaming.org/forums/index.php?topic=14936.0
http://www.java-gaming.org/forums/index.php?topic=14866.0

There was a big 6+ page epic but I couldn’t find that one. (Or rather, I think I found it but got redirected to an old version of the forums and a “closed for maintenance” message :frowning: )

there are also topic already talking about Thread.sleep accuracy, sry I dont make a search as big as yours (I only do a search in topic) but i guess there are many more thread talking about Thread.sleep accuracy…, this is a forum… do you think an answer like have a look to those xx links will help him? I mean that giving him an information “related” to his question is good, no ? or next time i will simply answer hey man try a search on the forum! or google it!

http://www.java-gaming.org/forums/index.php?topic=7579.0
http://www.java-gaming.org/forums/index.php?topic=3711.0

[quote]Works on all platforms.
[/quote]
that’ cool, i will definitly use it, thanks

[quote]We always change screen refresh rate to 60Hz if it’s available and turn vsync on; if we can’t get 60Hz, or vsync is definitely off, the timing is as accurate as we can get it using org.lwjgl.Sys.getTime() and Thread.sleep(0). We use the timer regardless of whether we think we’ve got vsync and 60Hz. Occasionally we drop a few frames when some other thing happens that slows the game down or we’re drawing just a bit too much for a crappy video card; big deal 99% of systems work smooth and perfect 99.9% of the time using the method we’ve stuck with since 2003.
[/quote]
so it sure that it is a very good method too, but i still prefer time-based :wink:

EDIT:hum… it seems that you definitly dont like to talk about that :wink:

quote from you comming from one of your links http://www.java-gaming.org/forums/index.php?topic=14936.0

[quote]Fixed vs. variable rate logic and fixed vs. variable rendering is an old topic thats been done to death on these forums, a quick search would be a good idea. Basically theres advantages and disadvantages to both, depending on your game requirements one may be a better choice than the other.
[/quote]

Thanks DzzD (and others) for your responses. I did try your suggestions and was able to get a steady rate of 10 millisecond waits.

I’m still playing around with which changes made the most difference, but I had to apply almost all of them to get the desired result

I will also include the Thread.sleep call and see if I can reproduce the problem from before.

Please don’t do that. I can’t stand 60 Hz refresh rates.

Provided you’re changing to the same or a smaller resolution, you should be able to keep the current (desktop) refresh rate.

Play any of my games and tell me that you notice it’s changed you to 60Hz while you’re playing.

Cas :slight_smile: