I'm doing some tasks using Java. I have some problems with timing: I need to set up a timer with a fixed period of repetition. I tried both, the standard Timer, and TimerTask and the ScheduledExecutor, but both work in an approximate manner, i.e. if I set an interval of 40 milliseconds, using the following code (for Executors)
m_executor = Executors.newScheduledThreadPool(5);
Runnable thread = new TheThread();
m_executor.scheduleWithFixedDelay(thread, 0, 40000000, TimeUnit.NANOSECONDS);
And then I try to print "time" of each execution
private static final class TheThread implements Runnable {
#Override
public void run() {
System.out.println(System.nanoTime()/1000000);
}
}
The result is something like this:
xxxxxx300
xxxxxx345
xxxxxx386
xxxxxx428
...
As you can see, if I correctly understand nanoTime() the function is called at a random intervals, close to that I specified (40 milliseconds), but not exactly what I specified!
When I worked with C and Win32s, for example, I was able to use the CreateTimerQueueTimer() function that is highly accurate, and the callback function was called every 40 milliseconds:
xxxxxx300
xxxxxx340
xxxxxx380
...
I tried to move time measurement to avoid the printing time. I also tried to use scheduleAtFixedRate(), but unfortunately the period varies between 35 and 47 ms (set to 40 in the method).
I'm wondering how people can make software such emulators or similar things, that requires a precise period observance...:-)
I thought of a possible solution that I would like to show you and ask to you, experts:) how this idea could be applicable (and safe)
The problem here is to run some methods every X milliseconds, say 40 ms. The question here is about Java timer/timing, but what about this simple solution?
public class MyEmulator extends Thread {
private long start = 0;
private long end = 0;
#Override
public void run() {
long exec_time;
start = System.nanoTime();
/*
* Do the emulator-loop
*/
end = System.nanoTime();
exe_time = (end - start)/1000000;
// wait with a whil() (40 - exec_time)
}
}
With this solution, when I print the elapsed time after the waiting whilt() is ended the result is exactly 40 ms (without decimal, that is not quit important).
Do you think it would be safe, i.e. are really 40 ms?
I don't think you're going to be able to manage this in Java with this level of precision. Unlike your C/Win32 solutions, your Java solution is running in a JVM with multiple threads (of varying priority) and with garbage collection running and taking resources.
Having said that, I would experiment with the scheduleAtFixedRate() method, which executes at a regular period. scheduleWithFixedDelay() will execute and upon completion delay for a fixed amount of time. Hence not accounting for the time taken for your method to actually run.
Related
Let's say I implemented a method which sleeps the current thread for 10 seconds. Now I want to write a unit test case to test the functionality of this method. How can I do this? Is the below code a better option?
#Test
public void testSleep() {
long start = System.currentTimeMillis();
invokeFunction(2000);
long end = System.currentTimeMillis();
Assert.assertTrue(end - start > 2000);
}
I would say the code you attached is a fine test to test that the duration of invokeFunction(2000) does indeed take at least 2000ms. Though, it doesn't prove that the function takes roughly the amount of time you spec.
#Test
public void testSleep() {
for(int i=250; i<3000; i+= 250) {
long start = System.currentTimeMillis();
invokeFunction(i);
long end = System.currentTimeMillis();
Assert.assertTrue(end - start >= i);
Assert.assertTrue(end - start <= i+ 250);
}
}
This way you can show that the function takes roughly the amount of time give to it, with a tolerance of 250ms. With your original test if the invokeFunction method was hardcoded to sleep for 5000ms then your test would pass, but the implementation would not actually be correct.
i would say it depends what you want to test. you are not testing that the function actually sleeps thread X seconds, you are testing that the method takes at least X seconds to complete.
I mean, if the function is doing more things than just Thread.sleep, you are counting all of the stuff.
Note that i say at least, since there is no guarantee that the thread will sleep this amount of time exactly; it may take more time to awake (jvm will do its best).
but TBH i don't know of any other better approach than what you are doing, without doing changes in your function implementation just for the sake of being able to test that (like having an intermediate component which only purpose is just to sleep the thread and just monitor enter and exit from that component).
I have a Java application that is used to communicate with an embedded device over a UART connection (RS422). The host queries the microcontroller for data in 5 millisecond intervals. Up until recently I've been using ScheduledExecutorService scheduleAtFixedRate to call my communication protocol method, but it turns out scheduleAtFixedRate is very unreliable for this desired level of precision (as many other posts reveal). Among the data returned from the microcontroller is a timestamp (in microseconds), allowing me to verify the interval between received data packets independently of the JVM. Needless to say, the interval when using scheduleAtFixedRate varied wildly - up to 30 milliseconds between packets. Additionally, the scheduler will then try to overcompensate for the missed cycles by calling the Runnable several times within one millisecond (again, no surprise to anyone here).
After some searching, there seemed to be a consensus that the JVM simply could not be trusted to ensure any kind of precise scheduling. However, I decided to do some experimenting on my own and came up with this:
Runnable commTask = () -> {
// volatile boolean controlled from the GUI
while(deviceConnection) {
// retrieve start time
startTime = System.nanoTime();
// time since commProtocol was last called
timeDiff = startTime - previousTime;
// if at least 5 milliseconds has passed
if(timeDiff >= 5000000) {
// handle communication
commProtocol();
// store the start time for comparison
previousTime = startTime;
}
}
};
// commTask is started as follows
service = Executors.newSingleThreadScheduledExecutor();
service.schedule(commTask, 0, TimeUnit.MILLISECONDS);
The result of this was fantastic. Adjacent timestamps never varied by more than 0.1 milliseconds from the expected 5 millisecond interval. Despite this, something about this technique doesn't seem right, but I haven't been able to come up with anything else that works. My question is basically whether or not this approach is OK, and if not, what should I do instead?
(I am running Windows 10 with JDK 8_74)
Based on the information I've received in the comments, I've decided to use leave my code essentially intact (with the exception of Thread.yield() which I've added to the while loop). I have used this for a few months now and am very satisfied with the performance from this approach. See the final code below.
Runnable commTask = () -> {
// volatile boolean controlled from the GUI
while(deviceConnection) {
// retrieve start time
startTime = System.nanoTime();
// time since commProtocol was last called
timeDiff = startTime - previousTime;
// if at least 5 milliseconds has passed
if(timeDiff >= 5000000) {
// handle communication
commProtocol();
// store the start time for comparison
previousTime = startTime;
}
Thread.yield();
}
};
// commTask is started as follows
service = Executors.newSingleThreadScheduledExecutor();
service.execute(commTask);
I’m dealing with multithreading in Java and, as someone pointed out to me, I noticed that threads warm up, it is, they get faster as they are repeatedly executed. I would like to understand why this happens and if it is related to Java itself or whether it is a common behavior of every multithreaded program.
The code (by Peter Lawrey) that exemplifies it is the following:
for (int i = 0; i < 20; i++) {
ExecutorService es = Executors.newFixedThreadPool(1);
final double[] d = new double[4 * 1024];
Arrays.fill(d, 1);
final double[] d2 = new double[4 * 1024];
es.submit(new Runnable() {
#Override
public void run() {
// nothing.
}
}).get();
long start = System.nanoTime();
es.submit(new Runnable() {
#Override
public void run() {
synchronized (d) {
System.arraycopy(d, 0, d2, 0, d.length);
}
}
});
es.shutdown();
es.awaitTermination(10, TimeUnit.SECONDS);
// get a the values in d2.
for (double x : d2) ;
long time = System.nanoTime() - start;
System.out.printf("Time to pass %,d doubles to another thread and back was %,d ns.%n", d.length, time);
}
Results:
Time to pass 4,096 doubles to another thread and back was 1,098,045 ns.
Time to pass 4,096 doubles to another thread and back was 171,949 ns.
... deleted ...
Time to pass 4,096 doubles to another thread and back was 50,566 ns.
Time to pass 4,096 doubles to another thread and back was 49,937 ns.
I.e. it gets faster and stabilises around 50 ns. Why is that?
If I run this code (20 repetitions), then execute something else (lets say postprocessing of the previous results and preparation for another mulithreading round) and later execute the same Runnable on the same ThreadPool for another 20 repetitions, it will be warmed up already, in any case?
On my program, I execute the Runnable in just one thread (actually one per processing core I have, its a CPU-intensive program), then some other serial processing alternately for many times. It doesn’t seem to get faster as the program goes. Maybe I could find a way to warm it up…
It isn't the threads that are warming up so much as the JVM.
The JVM has what's called JIT (Just In Time) compiling. As the program is running, it analyzes what's happening in the program and optimizes it on the fly. It does this by taking the byte code that the JVM runs and converting it to native code that runs faster. It can do this in a way that is optimal for your current situation, as it does this by analyzing the actual runtime behavior. This can (not always) result in great optimization. Even more so than some programs that are compiled to native code without such knowledge.
You can read a bit more at http://en.wikipedia.org/wiki/Just-in-time_compilation
You could get a similar effect on any program as code is loaded into the CPU caches, but I believe this will be a smaller difference.
The only reasons I see that a thread execution can end up being faster are:
The memory manager can reuse already allocated object space (e.g., to let heap allocations fill up the available memory until the max memory is reached - the Xmx property)
The working set is available in the hardware cache
Repeating operations might create operations the compiler can easier reorder to optimize execution
Traceview shows that updatePhysics() is being called every 10ms or so and it takes about 8ms to run. The methods that I call inside updatePhysics are only running once every 5 or 6 times updatePhysics() runs, however. Is this simply a bug of Traceview, or what is going on? My game is stuttering a fair amount, so I am trying to figure out what is causing it.
Traceview is generally showing that a lot of my methods go several hundred milliseconds without being called once, even though there appears to be no reason they shouldnt be called. Ideas?
Run Method:
while (mRun)
{
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Canvas c = null;
try
{
c = mSurfaceHolder.lockCanvas(null);//null
{
time2 = System.nanoTime()/100000; // Get current time
float delta = (time2 - time1)/1000f;
if (mMode == STATE_RUNNING) updatePhysics(delta);
else updateMenus();
doDraw(c);
time1 = time2;
}
} finally
{
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null)
{
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
Update Physics:
private void updatePhysics(float delta)
{
updateScore(delta);
updateDifficulty();
}
EDIT: As you can see here, updateDifficulty is often not called for several hundred ms EVEN THOUGH updatePhysics is being called regularly... It makes no sense. Screenshot of traceview
Most likely somewhere in your thread you're calling thread.Sleep(0) or thread.Yield() or something like that. This will cause a thread to yield to other threads that are being scheduled. And it will often take 10ms or more before the thread gets scheduled back in. I think traceview doesn't understand this fully and counts the time the thread is in suspended state as being active.
Most games use a constant game loop, a real while(true) that never yields to anything.
Some other comments:
I would try the code without the try-catch block, this will slow things down considerabely. Als remove the threadpriority line, this is an OS call and could be slow, and would not add any speed in case of a bug. (It should be fine on normal priority)
Also are you sure this is correct:
time2 = System.nanoTime()/100000; // Get current time
float delta = (time2 - time1)/1000f;
I don't see why you require to devide the delta and the current time. Either convert the time from nanotime to seconds (or whatever you require), and then have a delta in seconds. Or keep time in nanoseconds and convert the delta to seconds. Now you first convert to seconds and then to 1/1000th of a second.
One of my friends showed me something he had done, and I was at a serious loss to explain how this could have happened: he was using a System.nanotime to time something, and it gave the user an update every second to tell how much time had elapsed (it Thread.sleep(1000) for that part), and it took seemingly forever (something that was waiting for 10 seconds took roughly 3 minutes to finish). We tried using millitime in order to see how much time had elapsed: it printed how much nanotime had elapsed every second, and we saw that for every second, the nanotime was moving by roughly 40-50 milliseconds every second.
I checked for bugs relating to System.nanotime and Java, but it seemed the only things I could find involved the nanotime suddenly greatly increasing and then stopping. I also browsed this blog entry based on something I read in a different question, but that didn't have anything that may cause it.
Obviously this could be worked around for this situation by just using the millitime instead; there are lots of workarounds to this, but what I'm curious about is if there's anything other than a hardware issue with the system clock or at least whatever the most accurate clock the CPU has (since that's what System.nanotime seems to use) that could cause it to run consistently slow like this?
long initialNano = System.nanoTime();
long initialMili = System.currentTimeMillis();
//Obviously the code isn't actually doing a while(true),
//but it illustrates the point
while(true) {
Thread.sleep(1000);
long currentNano = System.nanoTime();
long currentMili = System.currentTimeMillis();
double secondsNano = ((double) (currentNano - initialNano))/1000000000D;
double secondsMili = ((double) (currentMili - initialMili))/1000D;
System.out.println(secondsNano);
System.out.println(secondsMili);
}
secondsNano will print something along the lines of 0.04, whereas secondsMili will print something very close to 1.
It looks like a bug along this line has been reported at Sun's bug database, but they closed it as a duplicate, but their link doesn't go to an existing bug. It seems to be very system-specific, so I'm getting more and more sure this is a hardware issue.
... he was using a System.nanotime to cause the program to wait before doing something, and ...
Can you show us some code that demonstrates exactly what he was doing? Was it some strange kind of busy loop, like this:
long t = System.nanoTime() + 1000000000L;
while (System.nanoTime() < t) { /* do nothing */ }
If yes, then that's not the right way to make your program pause for a while. Use Thread.sleep(...) instead to make the program wait for a specified number of milliseconds.
You do realise that the loop you are using doesn't take exactly 1 second to run? Firstly Thread.sleep() isn't guaranteed to be accurate, and the rest of the code in the loop does take some time to execute (Both nanoTime() and currentTimeMillis() actually can be quite slow depending on the underlying implementation). Secondly, System.currentTimeMillis() is not guaranteed to be accurate either (it only updates every 50ms on some operating system and hardware combinations). You also mention it being inaccurate to 40-50ms above and then go on to say 0.004s which is actually only 4ms.
I would recommend you change your System.out.println() to be:
System.out.println(secondsNano - secondsMili);
This way, you'll be able to see how much the two clocks differ on a second-by-second basis. I left it running for about 12 hours on my laptop and it was out by 1.46 seconds (fast, not slow). This shows that there is some drift in the two clocks.
I would think that the currentTimeMillis() method provides a more accurate time over a large period of time, yet nanoTime() has a greater resolution and is good for timing code or providing sub-millisecond timing over short time periods.
I've experienced the same problem. Except in my case, it is more pronounced.
With this simple program:
public class test {
public static void main(String[] args) {
while (true) {
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
OStream.out("\t" + System.currentTimeMillis() + "\t" + nanoTimeMillis());
}
}
static long nanoTimeMillis() {
return Math.round(System.nanoTime() / 1000000.0);
}
}
I get the following results:
13:05:16:380 main: 1288199116375 61530042
13:05:16:764 main: 1288199117375 61530438
13:05:17:134 main: 1288199118375 61530808
13:05:17:510 main: 1288199119375 61531183
13:05:17:886 main: 1288199120375 61531559
The nanoTime is showing only ~400ms elapsed for each second.