Java "scheduleAtFixedRate" alternative solution? - java

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

Related

How can I write a unit test to test the functionality of Thread.Sleep?

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

Java real fixed time interval

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.

Update current time date without exploding in memory

I have written the following Java code:
Calendar now = Calendar.getInstance();
now.setTime(new Date());
Date currentDate = null;
while (now.compareTo(stop) < 0 ) {
currentDate = new Date();
now.setTime(currentDate);
}
that is meant to track down the time passing while other components (in particular: a Twitter Streaming listener) perform other actions. So, this is not meant to be a simple sleep, since other components are running in the meanwhile: this loop is just meant to keep the machine occupied for a while, until the date indicated by stop arrives.
However, by doing this the memory size keeps increasing a lot. I profiled the thing and I saw that this generates a huge amount of Date objects in memory.
Is there a smarter way of doing this?
Thank you in advance.
The minimum change is to use setTimeInMillis using System.currentTimeMillis rather than setTime:
while (now.compareTo(stop) < 0 ) { // Ugh, busy wait, see below
now.setTimeInMillis(System.currentTimeMillis());
}
...or actually, just use milliseconds in the first place:
long stopAt = stop.getTimeMillis();
while (System.currentTimeMillis() < stopAt) { // Ugh, busy wait, see below
}
However, surely with broader context there's a way to avoid busy-waiting at all. Busy-waits are almost never appropriate.
So, this is not meant to be a simple sleep, since other components are running in the meanwhile: this loop is just meant to keep the machine occupied for a while, until the date indicated by stop arrives.
Presumably those components are running on other threads, as your while loop is a busy-wait.
That being the case, this thread should sleep — either for a period of time, or until it's woken up by something else.
For instance, you haven't said what stop is, but as you're using it with compareTo presumably it's a Calendar. So it should be possible to get the difference (in milliseconds, via getTimeInMillis) between stop and now, and sleep rather than busy-waiting:
Calendar now = Calendar.getInstance(); // Initializes to "now", no need to do that yourself
long delay = stop.getTimeInMillis() - now.getTimeInMillis();
if (delay > 0) {
Thread.sleep(delay);
}

Calculating time difference in Milliseconds

I am making a call to a method by passing ipAddress and it will return back the location of ipAddress like Country, City, etc etc. So I was trying to see how much time it is taking for each call. So I set the start_time before making call to method and end_time after making a call. So sometimes I get difference as 0. And resp contains the valid response.
long start_time = System.currentTimeMillis();
resp = GeoLocationService.getLocationIp(ipAddress);
long end_time = System.currentTimeMillis();
long difference = end_time-start_time;
So that means sometimes it is taking 0 ms to get the response back. Any suggestions will be appreciated.
Try this
long start_time = System.nanoTime();
resp = GeoLocationService.getLocationByIp(ipAddress);
long end_time = System.nanoTime();
double difference = (end_time - start_time) / 1e6;
I pretty much like the (relatively) new java.time library: it's close to awesome, imho.
You can calculate a duration between two instants this way:
import java.time.*
Instant before = Instant.now();
// do stuff
Instant after = Instant.now();
long delta = Duration.between(before, after).toMillis(); // .toWhatsoever()
API is awesome, highly readable and intuitive.
Classes are thread-safe too. !
References: Oracle Tutorial, Java Magazine
No, it doesn't mean it's taking 0ms - it shows it's taking a smaller amount of time than you can measure with currentTimeMillis(). That may well be 10ms or 15ms. It's not a good method to call for timing; it's more appropriate for getting the current time.
To measure how long something takes, consider using System.nanoTime instead. The important point here isn't that the precision is greater, but that the resolution will be greater... but only when used to measure the time between two calls. It must not be used as a "wall clock".
Note that even System.nanoTime just uses "the most accurate timer on your system" - it's worth measuring how fine-grained that is. You can do that like this:
public class Test {
public static void main(String[] args) throws Exception {
long[] differences = new long[5];
long previous = System.nanoTime();
for (int i = 0; i < 5; i++) {
long current;
while ((current = System.nanoTime()) == previous) {
// Do nothing...
}
differences[i] = current - previous;
previous = current;
}
for (long difference : differences) {
System.out.println(difference);
}
}
}
On my machine that shows differences of about 466 nanoseconds... so I can't possibly expect to measure the time taken for something quicker than that. (And other times may well be roughly multiples of that amount of time.)
Since Java 1.5, you can get a more precise time value with System.nanoTime(), which obviously returns nanoseconds instead.
There is probably some caching going on in the instances when you get an immediate result.
From Java 8 onward you can try the following:
import java.time.*;
import java.time.temporal.ChronoUnit;
Instant start_time = Instant.now();
// Your code
Instant stop_time = Instant.now();
System.out.println(Duration.between(start_time, stop_time).toMillis());
//or
System.out.println(ChronoUnit.MILLIS.between(start_time, stop_time));
I do not know how does your PersonalizationGeoLocationServiceClientHelper works. Probably it performs some sort of caching, so requests for the same IP address may return extremely fast.
In the old days (you know, anytime before yesterday) a PC's BIOS timer would "tick" at a certain interval. That interval would be on the order of 12 milliseconds. Thus, it's quite easy to perform two consecutive calls to get the time and have them return a difference of zero. This only means that the timer didn't "tick" between your two calls. Try getting the time in a loop and displaying the values to the console. If your PC and display are fast enough, you'll see that time jumps, making it look as though it's quantized! (Einstein would be upset!) Newer PCs also have a high resolution timer. I'd imagine that nanoTime() uses the high resolution timer.
In such a small cases where difference is less than 0 milliseconds you can get difference in nano seconds as well.
System.nanoTime()
You can use
System.nanoTime();
To get the result in readable format, use
TimeUnit.MILLISECONDS or NANOSECONDS

Traceview shows some methods arent being called for 200ms or more

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.

Categories

Resources