Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (538)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (600)
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(). A problem. Any ideas?  (Read 4992 times)
0 Members and 1 Guest are viewing this topic.
Offline JoshuaDH

Junior Newbie





« Posted 2008-03-31 00:58:12 »

I'm having trouble with Thread.sleep().  I'm telling it to sleep 16.666667 milliseconds, but it seems like every 7th-10th call it sleeps for twice as long. 

Here's the code:

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  
public void run() {
      try {
         
         double sleepTime = 16.666667;
         while( true ) {  
           
            timeStep();
           
            int milli = (int)sleepTime;
            int nano = (int)((sleepTime - milli)*1000000);
           
            long startSleep = System.currentTimeMillis();
            Thread.sleep( milli, nano );
            long finishSleep = System.currentTimeMillis();
           
            System.out.println(finishSleep - startSleep);
           
         }
         
      }catch( InterruptedException e ) {
         //TODO:  Crash Nicely
         System.out.println("Crashed in Game Loop");
         e.printStackTrace();
         System.exit(1);
      }
   }


I've simplified it in some places that don't matter.  The important part is this:

1  
2  
3  
4  
5  
long startSleep = System.currentTimeMillis();//This is debug code
Thread.sleep( milli, nano );
long finishSleep = System.currentTimeMillis();//This is debug code
           
System.out.println(finishSleep - startSleep);//this is debug code
 

I expect that this will print 16-17 everytime it prints. Maybe sometimes 14-18.  Small variances wouldn't make much of a difference, but huge ones do. This is the output I get:

Quote
31
16
15
16
16
15
16
16
31
15
16
16
15
16
16
15
31
16
16
15
16
16
15
16
31
16
15
16
16
15
16
31
16
15
16

You can see that every 10 frames or so it's sleeping for what appears to be about twice as long.  Does anyone have any idea why this is happening?  I can develop a really crappy work around, but I'd rather not have to.  Any ideas would be appreciated.

Thanks,

-Josh
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #1 - Posted 2008-03-31 01:15:33 »

Sleep isn't very accurate. Take a look at lwjgl's Display.sync method. It's the most robust throttling scheme I know. (Well, I wrote it, but I did a lot of research and testing beforehand. It really doesn't get any better than that.)

弾幕 ☆ @mahonnaiseblog
Offline JoshuaDH

Junior Newbie





« Reply #2 - Posted 2008-03-31 01:22:26 »

If my game thread isn't directly handling rendering, can I still use Display.sync?  The loop is entirely logic.  There's no graphics in there.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #3 - Posted 2008-03-31 05:01:12 »

If you only want to throttle this one loop, yes. Otherwise it's a bad idea, because it uses some class variables.

Well, the code is available. You can copy&paste it over if you like.

弾幕 ☆ @mahonnaiseblog
Offline irrisor

Junior Devvie





« Reply #4 - Posted 2008-03-31 07:55:31 »

sleep is more accurate than currentTimeMillis on Windows Tongue - use nanoTime in JRE 1.5 to get more reliable measurements
Offline Markus_Persson

JGO Wizard


Medals: 16
Projects: 19


Mojang Specifications


« Reply #5 - Posted 2008-03-31 08:59:48 »

use nanoTime in JRE 1.5 to get more reliable measurements

Except that nanotime can totally freak out on some cpus (some (most?) dual core amds, for example) and start jumping back and forth between two different (slightly out of phase) timers.

Negative game render time? It happens.

Play Minecraft!
Offline princec

« JGO Spiffy Duke »


Medals: 429
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #6 - Posted 2008-03-31 09:22:49 »

Didn't they put some workarounds in for that?

Cas Smiley

Offline irrisor

Junior Devvie





« Reply #7 - Posted 2008-03-31 09:53:27 »

Except that nanotime can totally freak out on some cpus
in some jre versions - that's true *sigh*... use your stopwatch Roll Eyes
Offline DzzD
« Reply #8 - Posted 2008-03-31 13:28:16 »

the System.currentTimeMillis method on window have a low granularity around 16.xxx, this means that :
realtime = 1 => currentTimeMillis = 0
realtime = 2 => currentTimeMillis = 0
realtime = 10 => currentTimeMillis = 0
realtime = 15 => currentTimeMillis = 15
realtime = 17 => currentTimeMillis = 15
realtime = 20 => currentTimeMillis = 15
realtime = 25 => currentTimeMillis = 15
realtime = 30 => currentTimeMillis = 15
realtime = 32 => currentTimeMillis = 32
etc....

so if you got 0 it mean between 0 and 15
so if you got 15 it mean between 15 and 32
and etc...

Thread.sleep is more accurate but as you dont know the real time you cannot know how long you have to sleep/wait !!

below is the implementation I used wich give good results for me (maximum allowed fps == 1000/16 aprrox 62fps)

iTimer.getTime() return System.currentTimeMillis

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  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
this.fpsBuffer=new long[50];
this.maxFPS100=3000; //30 fps

thread run method:  
public void run()
{
try
{
 while(this.runProcess)
  {
   if(!this.pauseProcess)
   {
    //Make sure that we dont render twice a frame in the same timer ticks
    currentTime=this.iTimer.getTime()-this.startTime;
    while(currentTime==lastCurrentTime)
    {
     currentTime=this.iTimer.getTime()-this.startTime;
     Thread.sleep(1);
   }
    lastCurrentTime=currentTime;
    //Compute microsecond per frame using user selected FPS
    long frameTimeUs=100000000/this.maxFPS100;

    //Compute how many frame should have been rendered since start with frameTimeUs
    long nbFrameSinceStart=(1000*currentTime)/frameTimeUs;

    //Compute what should be the next frame millisecond rendering time
    long currentFrameTimeMs=((nbFrameSinceStart+1)*frameTimeUs)/1000;

    //Ensure that we dont render twice same frame
    if(lastCurrentFrameTimeMs==currentFrameTimeMs)
     currentFrameTimeMs=lastCurrentFrameTimeMs+frameTimeUs/1000;

    if((currentFrameTimeMs-lastCurrentFrameTimeMs)>(frameTimeUs/1000))
      currentFrameTimeMs=lastCurrentFrameTimeMs+frameTimeUs/1000;
               
    lastCurrentFrameTimeMs=currentFrameTimeMs;
               
    while(currentTime<currentFrameTimeMs)
   {
    overEatCPU=0;
    Thread.sleep(1);
    if(this.iTimer.getTime()-this.startTime==currentTime)
     currentTime++;
   else
    currentTime=this.iTimer.getTime()-this.startTime;
   }
               
   if(overEatCPU>1)
    Thread.yield();
                 
   overEatCPU++;
   this.fpsBuffer[this.numLoop%this.fpsBuffer.length]=currentTime+startTime;
   this.render();
   this.numLoop++;                  
               
   }
   else
   {
    Thread.sleep(1);
    Thread.yield();
   }
  }
 }
catch(InterruptedException ie)
{
 Log.log(ie);              
}
}

Offline Markus_Persson

JGO Wizard


Medals: 16
Projects: 19


Mojang Specifications


« Reply #9 - Posted 2008-03-31 13:49:57 »

Didn't they put some workarounds in for that?

Cas Smiley

Still happens for me, both at home and at work. As for java version, it auto-updated just a few days ago.

I've made my timer class detect if time ever runs backwards, then revert to using average tick times instead of actual measured tick times if it ever does. Seems to work sufficiently well.

Play Minecraft!
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Scarzzurs
« Reply #10 - Posted 2008-03-31 15:42:13 »

Wow. I had similiar problems with nanoTime, but i never really researched the results as it works on my own machines...
However now that i know this, I think i'll use the method Markus_Persson's suggested.

Thanks a lot for sharing this info all :-)

- Scarzzurs

My games and Projects:
BlastingPixels.com,
Old website
Offline JoshuaDH

Junior Newbie





« Reply #11 - Posted 2008-03-31 19:59:25 »

Yea, that's what I've done too.  I've implemented a method using nanoTime, but if I get a negative elapsed time reading, I switch to another algorithm I wrote that does pretty well at keeping up. 

Thanks for the info guys.  Does anyone know when Sun plans on fixing that nanoTime bug?


-Josh
Offline irrisor

Junior Devvie





« Reply #12 - Posted 2008-04-01 07:51:35 »

It's an OS/Processor bug, I believe.
Offline Markus_Persson

JGO Wizard


Medals: 16
Projects: 19


Mojang Specifications


« Reply #13 - Posted 2008-04-01 11:20:18 »

Still, it renders nanotime pretty much useless for proper timing. There are other ways of measuring time, just not from pure java.

Play Minecraft!
Offline princec

« JGO Spiffy Duke »


Medals: 429
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #14 - Posted 2008-04-01 13:12:00 »

We seem to do ok with the LWJGL timer. No idea how it stacks up on Linux or Mac but haven't had any reports.

Cas Smiley

Offline irrisor

Junior Devvie





« Reply #15 - Posted 2008-04-01 13:28:47 »

yeah LWJGL timer is fine (ms accuracy) but you need that nasty native lib Undecided
Offline Markus_Persson

JGO Wizard


Medals: 16
Projects: 19


Mojang Specifications


« Reply #16 - Posted 2008-04-01 13:46:57 »

We seem to do ok with the LWJGL timer.

Yeah, that one is a thing of beauty. =)
*modifies post to say "pure java"*

Play Minecraft!
Offline princec

« JGO Spiffy Duke »


Medals: 429
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #17 - Posted 2008-04-01 14:18:58 »

Seeing as the lib is all properly signed and available on any useful widespread platform out there... does it really matter?

Cas Smiley

Offline Markus_Persson

JGO Wizard


Medals: 16
Projects: 19


Mojang Specifications


« Reply #18 - Posted 2008-04-01 18:00:44 »

Well, yes, it won't work in (unsigned, so the user doesn't have to trust me) applets.

Play Minecraft!
Offline darkprophet

Senior Devvie




Go Go Gadget Arms


« Reply #19 - Posted 2008-04-03 16:38:15 »

Regarding the AMD Dual Core nanotime bug, AMD have released a utility in August of 2007 that seams to resolve this issue:

From their website:

Quote
The AMD Dual-Core Optimizer can help improve some PC gaming video performance by compensating for those applications that bypass the Windows API for timing by directly using the RDTSC (Read Time Stamp Counter) instruction. Applications that rely on RDTSC do not benefit from the logic in the operating system to properly account for the affect of power management mechanisms on the rate at which a processor core's Time Stamp Counter (TSC) is incremented. The AMD Dual-Core Optimizer helps to correct the resulting video performance effects or other incorrect timing effects that these applications may experience on dual-core processor systems, by periodically adjusting the core time-stamp-counters, so that they are synchronized.

http://www.amd.com/us-en/Processors/TechnicalResources/0,,30_182_871_13118,00.html

DP Smiley

Friends don't let friends make MMORPGs.

Blog | Volatile-Engine
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.

rwatson462 (28 views)
2014-12-15 09:26:44

Mr.CodeIt (19 views)
2014-12-14 19:50:38

BurntPizza (35 views)
2014-12-09 22:41:13

BurntPizza (70 views)
2014-12-08 04:46:31

JscottyBieshaar (32 views)
2014-12-05 12:39:02

SHC (44 views)
2014-12-03 16:27:13

CopyableCougar4 (40 views)
2014-11-29 21:32:03

toopeicgaming1999 (108 views)
2014-11-26 15:22:04

toopeicgaming1999 (94 views)
2014-11-26 15:20:36

toopeicgaming1999 (29 views)
2014-11-26 15:20:08
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
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!