I have been researching and I am struggling to actually choose the best option. I am using processing sketch that runs java code, and I want to start an animation in several computers( OS X and windows) at the same time. The basic idea is to send a OSC message to each computer and after they receive a message they will store the currentTime plus the timespan(let say after 10 second). And each computer track the currentTime and when it reach the intended Time they will start the animation. Now I cannot figure out which System should I use. System.currentTimeMillis() or System.nanoTime(); I already tested with two computers(both Systems) and it seems to work. Both computers are OS X but I never tried with a windows one and it seems for System.currentTimeMillis() can be a lag of 50ms. I'm really confuse in this matter. Someone can me explain or highlight.
thank in advance
Simultanous simulations on two or more computers is tricky for some reasons.
First of all I would make sure, all connected computers synchronize their clocks with NTP. (See more https://en.wikipedia.org/wiki/Network_Time_Protocol)
Then the biggest difference is at most 50ms as far as I know.
Otherwise every approach will fail because of the differences of the clocks.
Second, clocks on different systems have different accuracy. I can recommend reading Alexey Shipilev's blog: https://shipilev.net/blog/2014/nanotrusting-nanotime/ . It is about the accuracy of clocks on machines in general.
Third you need to know that Linux has a round robin slide of 1ms and Windows about 10-15ms. Therefore Thread.sleep(...) will not work with smaller time spans reliable.
If you want to´work with smaller time spans you need to do a kind of "busy waiting" which is ugly but necessary:
public class SleepUtil {
public static final long MIN_PRECISION_IN_MICROS = 15L;
public static void main(String[] args) {
long before = System.nanoTime();
while (true) {
final long after = System.nanoTime();
long diff = (after - before) / 1000l;
before = after;
System.out.println(diff + " micros");
SleepUtil.sleepMicros(500);
}
}
private static void sleepMicros(int waitTimeInMicros) {
final long startTimeInNanos = System.nanoTime();
long elapsedTimeInMicros = 0L;
while (elapsedTimeInMicros < waitTimeInMicros - MIN_PRECISION_IN_MICROS) {
elapsedTimeInMicros = (System.nanoTime() - startTimeInNanos) / 1000L;
}
}
}
However, it will busy your cpu and not be always reliable (but most of the time).
Related
I am working on a small game project and want to track time in order to process physics. After scrolling through different approaches, at first I had decided to use Java's Instant and Duration classes and now switched over to Guava's Stopwatch implementation, however, in my snippet, both of those approaches have a big gap at the second call of runtime.elapsed(). That doesn't seem like a big problem in the long run, but why does that happen?
I have tried running the code below as both in focus and as a Thread, in Windows and in Linux (Ubuntu 18.04) and the result stays the same - the exact values differ, but the gap occurs. I am using the IntelliJ IDEA environment with JDK 11.
Snippet from Main:
public static void main(String[] args) {
MassObject[] planets = {
new Spaceship(10, 0, 6378000)
};
planets[0].run();
}
This is part of my class MassObject extends Thread:
public void run() {
// I am using StringBuilder to eliminate flushing delays.
StringBuilder output = new StringBuilder();
Stopwatch runtime = Stopwatch.createStarted();
// massObjectList = static List<MassObject>;
for (MassObject b : massObjectList) {
if(b!=this) calculateGravity(this, b);
}
for (int i = 0; i < 10; i++) {
output.append(runtime.elapsed().getNano()).append("\n");
}
System.out.println(output);
}
Stdout:
30700
1807000
1808900
1811600
1812400
1813300
1830200
1833200
1834500
1835500
Thanks for your help.
You're calling Duration.getNano() on the Duration returned by elapsed(), which isn't what you want.
The internal representation of a Duration is a number of seconds plus a nano offset for whatever additional fraction of a whole second there is in the duration. Duration.getNano() returns that nano offset, and should almost never be called unless you're also calling Duration.getSeconds().
The method you probably want to be calling is toNanos(), which converts the whole duration to a number of nanoseconds.
Edit: In this case that doesn't explain what you're seeing because it does appear that the nano offsets being printed are probably all within the same second, but it's still the case that you shouldn't be using getNano().
The actual issue is probably some combination of classloading or extra work that has to happen during the first call, and/or JIT improving performance of future calls (though I don't think looping 10 times is necessarily enough that you'd see much of any change from JIT).
Does anyone have a Fairly effective way of running a function repetitively in a precise and accurate number of milliseconds. I have tried to accomplish this by using the code below to try to run a function called wave() once a second for 30 seconds:
startTime = System.nanoTime();
wholeTime = System.nanoTime();
while (loop) {
if (startTime >= time2) {
startTime = System.nanoTime();
wave();
sec++;
}
if (sec == 30) {
loop = false;
endTime = System.nanoTime();
System.out.println(wholeTime - System.nanoTime());
}
}
}
This code did not work and am wondering why this code didn't work and if their is a better approach to the problem. Any ideas on how to improve fix the above code or other successful ways of accomplishing the problem are all welcome. Thank you for your help!
more simple:
long start=System.currentTimeMillis(); // Not very very accurate
while (System.currentTimeMillis()-start<30000)
{
wave();
// count something
}
You can use a Timer+TimerTask: https://docs.oracle.com/javase/7/docs/api/java/util/Timer.html
https://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html
http://bioportal.weizmann.ac.il/course/prog2/tutorial/essential/threads/timer.html
You may use Thread.sleep():
public static void main (String[] args) throws InterruptedException {
int count = 30;
long start = System.currentTimeMillis();
for(int i=0; i<count; i++) {
wave();
// how many milliseconds till the end of the second?
long sleep = start+(i+1)*1000-System.currentTimeMillis();
if(sleep > 0) // condition might be false if wave() runs longer than second
Thread.sleep(sleep);
}
}
Does anyone have a Fairly effective way of running a function repetitively in a precise and accurate number of milliseconds.
There is no way to do this kind of thing reliably and accurately in standard Java. The problem is that there is no way that you can guarantee that your thread will run when you want ti to run. For example:
your thread could be suspended to allow the GC to run
your thread could be preempted to allow another thread in your application to run
your thread could be suspended by the OS while it fetches pages by the JVM back from disk.
You can only get reliable behavior for this kind of code if you run on a hard realtime OS, and an realtime Java.
Note that this is not an issue with clock accuracy. The real problem is that the scheduler does not give you the kind of guarantees you need. For instance, none of the "sleep until X" functionality in a JVM can guarantee that your thread will wake up at time X exactly ... for any useful meaning of "exactly".
The other answers suggest various ways to do this, but beware that they are not (and cannot be) reliable and accurate in all circumstances .. or even on a typical machine running other things as well as your application.
Say, for example, I want to run the following program
double x = 15.6
System.out.println(x);
But I wanted to repeat the program until a certain time has elapsed, such as the following:
do{
double x = 15.6
System.out.println(x);
}while (current time is earlier than 12.00pm)
Even though the example is completely hypothetical, how would I make that do while loop so that the program would keep running over and over again until a certain time, say 3pm, or9.30pm.
If this is not possible, is there any way I can simulate this, by running the program every so many seconds, until that time has been reached?
a) You usually don't need the code to actually run until a time has come - you wouldn't have any control over the amount of times the code executed this way. Regular code has to sleep sometimes, to give control to OS and other processes so that they don't clog the system with 100% CPU load. As such, actually running the code constantly is a wrong approach to 99% of the possible problems related to timings. Please describe the exact problem you want to solve using this code.
b) For those 99% of problems, use a Timer instance. Simple as that. https://docs.oracle.com/javase/7/docs/api/java/util/Timer.html - schedule the task to run e.g. 1000 times a second, and check the time in each event, terminating the Timer instance when the time threshold has been exceeded.
For example, this code above will give you continuous execution of Do something part, every 1 second, until 16.11.2014 20:00 GMT. By changing delayMs you can easily achieve higher/lower time granularity. If you expect your code to be run more often than 1000/sec, you should probably use JNI anyway, since Java timers/clocks are known to have <10ms granularity on some (older) platforms, see How can I measure time with microsecond precision in Java? etc.
Timer timer = new Timer();
int delayMs = 1000; // check time every one second
long timeToStop;
try {
timeToStop = new SimpleDateFormat( "DD.MM.YYYY HH:mm" ).parse( "16.11.2014 20:00" ).getTime(); // GMT time, needs to be offset by TZ
} catch (ParseException ex) {
throw new RuntimeException( ex );
}
timer.scheduleAtFixedRate( new TimerTask() {
#Override
public void run() {
if ( System.currentTimeMillis() < timeToStop ) {
System.out.println( "Do something every " + delayMs + " milliseconds" );
} else {
timer.cancel();
}
}
}, 0, delayMs );
or you can use e.g. ExecutorService service = Executors.newSingleThreadExecutor(); etc. - but it's virtually impossible to give you a good way to solve your problem without explicitly knowing what the problem is.
Something like this
//get a Date object for the time to stop, then get milliseconds
long timeToStop = new SimpleDateFormat("DD:MM:HH:mm").parse("16:11:12:00").getTime();
//get milliseconds now, and compare to milliseconds from before
do {
//do stuff
} while(System.currentTimeMillis() < timeToStop)
In my client (using LWJGL), I use the following code:
private static long getTime() {
return (Sys.getTime() * 1000) / Sys.getTimerResolution();
}
However, I have also just finished coding a server for this game, and up until now, I am been using LWJGL only for the purpose of having that method in my code. Which really, is a bit impractical.
What is a suitable alternative for the above code that uses no libraries at all?
I think you might be looking for System.nanoTime() in the Java libraries. This method would obviously give you a long of the time, of which you could standardize into ticks.
// beginning of the game loop
long startTime = System.nanoTime();
// end of the game loop
long estimatedTime = System.nanoTime() - startTime;
You could divide this number by the amount of ticks you want per second (as Sys.getTimerResolution() does) and then you could have very similar operation to what the LWJGL library provides you.
Myself and another developer on my time recently moved from a Core 2 Duo machine at work to a new Core 2 Quad 9505; both running Windows XP SP3 32-bit with JDK 1.6.0_18.
Upon doing so, a couple of our automated unit tests for some timing/statistics/metrics aggregation code promptly started failing, due to what appear to be ridiculous values coming back from System.nanoTime().
Test code that shows this behaviour, reliably, on my machine is:
import static org.junit.Assert.assertThat;
import org.hamcrest.Matchers;
import org.junit.Test;
public class NanoTest {
#Test
public void testNanoTime() throws InterruptedException {
final long sleepMillis = 5000;
long nanosBefore = System.nanoTime();
long millisBefore = System.currentTimeMillis();
Thread.sleep(sleepMillis);
long nanosTaken = System.nanoTime() - nanosBefore;
long millisTaken = System.currentTimeMillis() - millisBefore;
System.out.println("nanosTaken="+nanosTaken);
System.out.println("millisTaken="+millisTaken);
// Check it slept within 10% of requested time
assertThat((double)millisTaken, Matchers.closeTo(sleepMillis, sleepMillis * 0.1));
assertThat((double)nanosTaken, Matchers.closeTo(sleepMillis * 1000000, sleepMillis * 1000000 * 0.1));
}
}
Typical output:
millisTaken=5001
nanosTaken=2243785148
Running it 100x yields nano results between 33% and 60% of the actual sleep time; usually around 40% though.
I understand the weaknesses in accuracy of timers in Windows, and have read related threads like Is System.nanoTime() consistent across threads?, however my understanding is that System.nanoTime() is intended for exactly the purpose we're using it :- measuring elapsed time; more accurately than currentTimeMillis().
Does anyone know why it's returning such crazy results? Is this likely to be a hardware architecture problem (the only major thing that has changed is the CPU/Motherboard on this machine)? A problem with the Windows HAL with my current hardware? A JDK problem? Should I abandon nanoTime()? Should I log a bug somewhere, or any suggestions on how I could investigate further?
UPDATE 19/07 03:15 UTC: After trying finnw's test case below I did some more Googling, coming across entries such as bugid:6440250. It also reminded me of some other strange behaviour I noticed late Friday where pings were coming back negative. So I added /usepmtimer to my boot.ini and now all the tests behave as expected., and my pings are normal too.
I'm a bit confused about why this was still an issue though; from my reading I thought TSC vs PMT issues were largely resolved in Windows XP SP3. Could it be because my machine was originally SP2, and was patched to SP3 rather than installed originally as SP3? I now also wonder whether I should be installing patches like the one at MS KB896256. Maybe I should take this up with the corporate desktop build team?
The problem was resolved (with some open suspicions about the suitability of nanoTime() on multi-core systems!) by adding /usepmtimer to the end of my C:\boot.ini string; forcing Windows to use the Power Management timer rather than the TSC. It's an open question as to why I needed to do this given I'm on XP SP3, as I understood that this was the default, however perhaps it was due to the manner in which my machine was patched to SP3.
On my system (Windows 7 64-Bit, Core i7 980X):
nanosTaken=4999902563
millisTaken=5001
System.nanoTime() uses OS-specific calls, so I expect that you are seeing a bug in your Windows/processor combination.
You probably want to read the answers to this other stack overflow question: Is System.nanoTime() completely useless?.
In summary, it would appear that nanoTime relies on operating system timers that may be affected by the presence of multiple core CPUs. As such, nanoTime may not be that useful on certain combinations of OS and CPU, and care should be taken when using it in portable Java code that you intend to run on multiple target platforms. There seems to be a lot of complaining on the web on this subject, but not much consensus on a meaningful alternative.
It is difficult to tell whether this is a bug or just normal timer variation between cores.
An experiment you could try is to use native calls to force the thread to run on a specific core.
Also, to rule out power management effects, try spinning in a loop as an alternative to sleep():
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.W32API;
public class AffinityTest {
private static void testNanoTime(boolean sameCore, boolean spin)
throws InterruptedException {
W32API.HANDLE hThread = kernel.GetCurrentThread();
final long sleepMillis = 5000;
kernel.SetThreadAffinityMask(hThread, new NativeLong(1L));
Thread.yield();
long nanosBefore = System.nanoTime();
long millisBefore = System.currentTimeMillis();
kernel.SetThreadAffinityMask(hThread, new NativeLong(sameCore? 1L: 2L));
if (spin) {
Thread.yield();
while (System.currentTimeMillis() - millisBefore < sleepMillis)
;
} else {
Thread.sleep(sleepMillis);
}
long nanosTaken = System.nanoTime() - nanosBefore;
long millisTaken = System.currentTimeMillis() - millisBefore;
System.out.println("nanosTaken="+nanosTaken);
System.out.println("millisTaken="+millisTaken);
}
public static void main(String[] args) throws InterruptedException {
System.out.println("Sleeping, different cores");
testNanoTime(false, false);
System.out.println("\nSleeping, same core");
testNanoTime(true, false);
System.out.println("\nSpinning, different cores");
testNanoTime(false, true);
System.out.println("\nSpinning, same core");
testNanoTime(true, true);
}
private static final Kernel32Ex kernel =
(Kernel32Ex) Native.loadLibrary(Kernel32Ex.class);
}
interface Kernel32Ex extends Kernel32 {
NativeLong SetThreadAffinityMask(HANDLE hThread, NativeLong dwAffinityMask);
}
If you get very different results depending on core selection (e.g. 5000ms on the same core but 2200ms on different cores) that would suggest that the problem is just natural timer variation between cores.
If you get very different results from sleeping vs. spinning, it is more likely due to power management slowing down the clocks.
If none of the four results are close to 5000ms, then it might be a bug.