Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (475)
Games in Android Showcase (106)
games submitted by our members
Games in WIP (530)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Thread.sleep accuracy?  (Read 3615 times)
0 Members and 1 Guest are viewing this topic.
Offline GDX

Senior Newbie





« Posted 2007-10-21 00:30:16 »

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...
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
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?
1  
Offline broumbroum

Junior Member





« Reply #1 - Posted 2007-10-21 00:48:49 »

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

::::... :..... :::::: ;;;:::™ b23:production 2006 GNU/GPL @ http://b23prodtm.webhop.info
on sf.net: /projects/sf3jswing
Java (1.6u10 plz) Web Start pool
dev' VODcast[/ur
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #2 - Posted 2007-10-21 01:38:45 »

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.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline GDX

Senior Newbie





« Reply #3 - Posted 2007-10-21 05:12:23 »

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?

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
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

Offline CommanderKeith
« Reply #4 - Posted 2007-10-21 06:45:21 »

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.  Smiley

Best regards,
Keith

Offline DzzD
« Reply #5 - Posted 2007-10-21 16:04:30 »

...
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.  Smiley
...

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 ;-)


Offline princec

JGO Kernel


Medals: 339
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #6 - Posted 2007-10-21 18:25:47 »

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 Smiley

Offline cylab

JGO Ninja


Medals: 38



« Reply #7 - Posted 2007-10-21 19:06:17 »

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.

Mathias - I Know What [you] Did Last Summer!
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #8 - Posted 2007-10-21 19:20:44 »

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 ;-)
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.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline brackeen

Junior Member





« Reply #9 - Posted 2007-10-21 20:31:30 »

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.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline GDX

Senior Newbie





« Reply #10 - Posted 2007-10-21 20:43:46 »

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.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
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
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 742
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #11 - Posted 2007-10-21 22:11:55 »

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.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline DzzD
« Reply #12 - Posted 2007-10-21 23:34:19 »

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.
oki

Quote
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.
I always notice 16/17ms on my computers, maybe it could be different depending on CPU.


Quote
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
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");
      }
   }
}

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
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
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;
      }
                         }

}



Offline DzzD
« Reply #13 - Posted 2007-10-21 23:45:51 »

Quote
Yield() tends to use the CPU unnecessarily; sleep(0) makes it look idle

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
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.

I think that's good to know about both method even if it is not the name of this thread....

Offline princec

JGO Kernel


Medals: 339
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #14 - Posted 2007-10-22 01:01:19 »

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 Smiley 99% of systems work smooth and perfect 99.9% of the time using the method we've stuck with since 2003.

Cas Smiley

Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #15 - Posted 2007-10-22 01:15:22 »

hey, that's a really interisting information, does that works for all platform ??

EDIT:
first sorry Orangy Tang ;-), but
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 :  
I think that's good to know about both method even if it is not the name of this thread....

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  Sad )

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline DzzD
« Reply #16 - Posted 2007-10-22 02:16:53 »


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.

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.
so it sure that it is a very good method too, but i still prefer time-based ;-)


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.




Offline GDX

Senior Newbie





« Reply #17 - Posted 2007-10-22 02:52:47 »

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.
Offline ajvaughan

Junior Newbie





« Reply #18 - Posted 2007-10-22 09:53:38 »

We always change screen refresh rate to 60Hz

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. 
Offline princec

JGO Kernel


Medals: 339
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #19 - Posted 2007-10-22 14:12:11 »

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

Cas Smiley

Offline broumbroum

Junior Member





« Reply #20 - Posted 2007-10-22 20:47:25 »

UltraTron is devastating...

::::... :..... :::::: ;;;:::™ b23:production 2006 GNU/GPL @ http://b23prodtm.webhop.info
on sf.net: /projects/sf3jswing
Java (1.6u10 plz) Web Start pool
dev' VODcast[/ur
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

ctomni231 (34 views)
2014-07-18 06:55:21

Zero Volt (30 views)
2014-07-17 23:47:54

danieldean (25 views)
2014-07-17 23:41:23

MustardPeter (27 views)
2014-07-16 23:30:00

Cero (42 views)
2014-07-16 00:42:17

Riven (44 views)
2014-07-14 18:02:53

OpenGLShaders (33 views)
2014-07-14 16:23:47

Riven (34 views)
2014-07-14 11:51:35

quew8 (30 views)
2014-07-13 13:57:52

SHC (66 views)
2014-07-12 17:50:04
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!