This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Cruor's profile picture

[1.7.10] Sleep sleeping for incorrect amount of ticks

Started by Cruor, 10 April 2015 - 04:19 PM
Cruor #1
Posted 10 April 2015 - 06:19 PM
MC 1.7.10, CraftOS 1.6, ComputerCraft1.65
Bug is also in latest beta (1.74pr20)

When sleeping for 0.2s towards 0.65s included, it adds another tick. Meaning a 0.2s sleep actually is 0.25, and so on.

Output from test program, first arg is sample count, second is time. (Yes, it is consistent with higher sample count)



Edit:
After decompiling the source, the problem seems to be in OSAPI.java

   public void advance(double dt) {
	  Map var3 = this.m_timers;
	  synchronized(this.m_timers) {
		 this.m_clock += dt;
		 Iterator previousTime = this.m_timers.entrySet().iterator();
		 while(previousTime.hasNext()) {
			Entry entry = (Entry)previousTime.next();
			OSAPI.Timer previousDay = (OSAPI.Timer)entry.getValue();
			previousDay.m_timeLeft -= dt;
			if(previousDay.m_timeLeft <= 0.0D) {
			   this.queueLuaEvent("timer", new Object[]{entry.getKey()});
			   previousTime.remove();
			}
		 }
	  }
The inaccuracy is caused by the use of doubles at the m_timeLeft -= dt;
Digging deeper, said method is called from ServerComputer.java

   public void update() {
	  super.update();
	  this.m_computer.advance(0.05D);
	  this.m_changedLastFrame = this.m_changed || this.m_computer.pollChanged();
	  this.m_computer.clearChanged();
	  this.m_changed = false;
	  ++this.m_ticksSincePing;
   }

Edit 2:
Proof that this is due to the use of doubles, and not tick alignment (or whatever other magical phenomenon you specify it under).
https://ideone.com/hqthf8
Incase Ideone doesn
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
  /* test 1 */
  double left1 = 0.65;
  int foo1 = 0;
 
  while (left1 > 0.0d) {
   left1 -= 0.05d;
   foo1++;
  }
 
  System.out.println(foo1);
 
  /* test 2 */
 
  double left2 = 0.7;
  int foo2 = 0;
 
  while (left2 > 0.0d) {
   left2 -= 0.05d;
   foo2++;
  }
 
  System.out.println(foo2);
}
}

Can this be changed to ticks represented in integers instead?
Edited on 19 May 2015 - 06:30 PM
Bomb Bloke #2
Posted 11 April 2015 - 12:07 AM
Also related.
Cruor #3
Posted 12 May 2015 - 05:08 PM
Added more details and potential solution.
theoriginalbit #4
Posted 12 May 2015 - 11:25 PM
Just FYI there isn't really a solution to this it will potentially always be off a little bit because OS timing isn't perfect either, if you tell a thread to sleep for 500 milliseconds (in Java: Thread.sleep(500)) then there is every chance it will sleep too long. If the computer cannot wake the thread at the desired time it cannot wake it instead it must wait until the next available chance, period.
Edited on 12 May 2015 - 09:26 PM
Cruor #5
Posted 19 May 2015 - 08:31 PM
Added Java code too show the problem with using doubles.
Edited on 19 May 2015 - 06:31 PM
theoriginalbit #6
Posted 20 May 2015 - 01:16 AM
Except that doubles have to be used otherwise you cannot sleep for fractions of a second. Also Lua only uses doubles, never ints.
dan200 #7
Posted 20 May 2015 - 08:45 PM
Fixed in next version