Java - too fast to recognize? - java

Complete code: https://github.com/Sheldor5/JavaGPP (see tests for both options)
I have some weird behaviors with command patterns and loops (counting down until the actual command action should be executed):
What I am trying to achieve:
I am currently developing a game and in this game I want to place a "bomb" and this "bomb" should explode in e.g. 2 seconds. I am doing this with command patterns where one type of command substracts thedelta from the left timeLeft variable until the timeLeft variable is <= zero --> so if the 2 seconds have passed the explosion should take place. This is not working if I execute the command in a while loop because the bomb explodes after +2.2 seconds and not after 2 (and some nanos). If I add a Thread.sleep(1) in the loop the time is accurate enough for me so I can say the calculation of the delta is done rigth.
Option 1:
// infinite loop: execute all commmands in the executor (only one command for now)
while (true) {
commandExecutor.executeCommands();
}
// the only one command in the executor gets called everytime
public static final long NANOS = 1000000000;
private long timeLeft = NANOS;
private long start;
public Command() {
this.start = System.nanoTime();
}
public execute(final long delta) {
this.timeLeft -= delta;
if (this.timeLeft <= 0) {
final long time = System.nanoTime() - this.start;
System.out.println(String.format("Successfully executed Command with ID '%s' in %dns (%dns)", this.getID(), time, this.timeLeft));
this.timeLeft += NANOS;
}
}
Expected Output (1 second interval):
Successfully executed Command with ID '1' in 1000000454ns (-454ns)
Successfully executed Command with ID '1' in 1000000695ns (-695ns)
Successfully executed Command with ID '1' in 1000000549ns (-549ns)
Successfully executed Command with ID '1' in 1000000003ns (-3ns)
Actual Output ():
Successfully executed Command with ID '1' in 1267062727ns (-266ns)
Successfully executed Command with ID '1' in 1350811695ns (-165ns)
Successfully executed Command with ID '1' in 1352353549ns (-145ns)
Successfully executed Command with ID '1' in 1263098003ns (-75ns)
But if I add a Thread.sleep() into the loop the actual output is much more accurate:
Option 2:
while (true) {
commandExecutor.executeCommands();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Acceptable Output:
Successfully executed Command4 with ID '40' in 1000015964ns (-47338ns)
Successfully executed Command4 with ID '40' in 1001095472ns (-316309ns)
Successfully executed Command4 with ID '40' in 1000039457ns (-224116ns)
Successfully executed Command4 with ID '40' in 1001043666ns (-662982ns)
Can someone explain this to me? Is the loop too fast? Is something so fast that it can't recognize the actual value of the variable and it wrongly sees it as greater than zero? Why there are so big differences and from where are those ~0.2 seconds?

Originally I thought this was a concurrency issue but I don't think it is because your custom executors and commands don't spawn any new threads. Instead I think that youre just instrumenting your time too much. Your code is basically just looping and calling System.nanotime(). The problem with the approach of using your delta variable is that you aren't taking into account the time involved in calling System.nantime (). But youre calling it a lot. I think that using a timer task would be be preferable but if you want to do this yourself try something like the following:
long start = System.nanotime ();
long inTwoSecs = start + 2000000000L;
while (true) {
long now = System.nanotime ();
if (now >= inTwoSecs) {
return;
}
}

Related

Why is there run time overhead on the first time a method is called in Java?

I was measuring execution time of my code and found some weird behavior when making the first call to a method (from the main method). Here is my code, please have a look at this
public static void main(String[] args) {
try (Scanner input = new Scanner(System.in)) {
int iNum = input.nextInt();
long lStartTime = System.nanoTime();
// ***********(First call in main) Calling isPrime *************
lStartTime = System.nanoTime();
printResult(isPrime(iNum));
System.out.println("Time Consumed in first call-: "
+ (System.nanoTime() - lStartTime));
// ***********(Second call in main) Calling isPrime *************
lStartTime = System.nanoTime();
printResult(isPrime(iNum));
System.out.println("Time Consumed in second call-: "
+ (System.nanoTime() - lStartTime));
}
}
private static boolean isPrime(int iNum) {
boolean bResult = true;
if (iNum <= 1 || iNum != 2 && iNum % 2 == 0) {
bResult = false;
} else {
double iSqrt = Math.sqrt((double) iNum);
for (int i = 3; i < iSqrt; i += 2) {
if (iNum % i == 0) {
bResult = false;
break;
}
}
}
return bResult;
}
private static void printResult(boolean bResult) {
if (bResult)
System.out.println("\nIt's prime number.");
else
System.out.println("\nIt's not prime number.");
}
Input
5
Output
It's prime number.
Time Consumed in first call-: 484073
It's prime number.
Time Consumed in second call-: 40710
Description
I have depicted only one test case of input and output above. But, there is always a difference in execution time between the first method invocation and the second one.
I have also tried more than two methods calls in the similar way and found that there is not such a huge difference between the other calls except one. I'm getting right execution time around 40710ns (this execution time could be different on your system) for the rest of calls except first method call which is 484073ns. Easily I can see that there is time overhead of 484073 - 40710 = 443363ns (approx) in first method call, but why is it happening? What is the root cause?
There are multiple implementations of the Java Runtime Environment, so not every implementation may behave like Oracle's (and previously Sun's).
That begin said the initial invocation of a method, in most current implementations, involves validation and a first pass compilation of the Java bytecode. Thus, subsequent invocations of the method, are faster. However, Java also uses a JIT. Wikipedia provides an entry on Just-in-time compilation which notes
JIT causes a slight delay to a noticeable delay in initial execution of an application, due to the time taken to load and compile the bytecode.
And, goes on to say,
The application code is initially interpreted, but the JVM monitors which sequences of bytecode are frequently executed and translates them to machine code for direct execution on the hardware.

Execute in future - time doubles somehow

I am very sorry to ask this question but something is going wrong with my code. Currently I am playing around with Command Patterns and I want a command class to execute code in the future - lets say 2 seconds in the future. The problem somehow is that the command gets executed in 5 seconds, not in 2??? Each call decreases a time variable until the variable is <= 0:
// 2 seconds in nanoseconds
private long timeLeft = 2000000000;
public boolean execute(final long delta) {
this.timeLeft -= delta;
if (this.timeLeft <= 0) {
// execute
this.timeLeft = 2000000000l;
return true
}
return false;
}
With lastExecution = System.nanoTime(); and then for each command delta = System.nanoTime() - lastExecution;
Full src on github: https://github.com/Sheldor5/JavaGPP
Instead of decrementing a countdown timer value by inaccurate deltas, calculate the target time and check for it, and use milli-time, not nano-time, to prevent sign issues.
long targetMillis = System.currentTimeMillis() + 2000; // 2 sec
while (System.currentTimeMillis() < targetMillis) {
// do something while we wait
}
// 2 secs elapsed, may be a bit more

Why this while loop cannot print 1,000 times per seconds?

The following Java method is meant to print the number i by nLoopsPerSecond times per second for seconds seconds:
public void test(int nLoopsPerSecond, int seconds) {
double secondsPerLoop = 1.0/(double)nLoopsPerSecond;
long startTime = System.currentTimeMillis();
long currentTime;
int i = 0;
while ((currentTime = System.currentTimeMillis()) < startTime + seconds*1000) {
System.out.println(i++);
while (System.currentTimeMillis() < currentTime + secondsPerLoop*1000);
}
}
With the following call:
test(1000,1);
I expect this method to do the System.out.println(i++); 1,000 times, but I only got 63.
When I try to see how many seconds it actually use per loop with this code
public void test(int nLoopsPerSecond, int seconds) {
double secondsPerLoop = 1.0/(double)nLoopsPerSecond;
long startTime = System.currentTimeMillis();
long currentTime;
int i = 0;
while ((currentTime = System.currentTimeMillis()) < startTime + seconds*1000) {
while (System.currentTimeMillis() < currentTime + secondsPerLoop*1000);
System.out.println(System.currentTimeMillis() - currentTime);
}
}
I expect it to print 1 milliseconds each loop, but it prints 15 or 16 milliseconds.
Please suggest what is wrong in my code.
Are you running on Windows, perhaps? System.currentTimeMillis() consults the underlying operating system clock, which is only 60Hz on many versions of Windows.
Try System.nanoTime() since you are not measuring time since the epoch. System.currentTimeMillis vs System.nanoTime
That's probably because the processing takes up some time. The processor does not solely dedicate its time to the execution of your program, it performs several other functions in the background. So you might get different results based on the processor load.
Your output console is not fast enough. You do not mention how you run your test and where the output goes. The speed of the terminal and buffers (not) used will limit how fast can the program output data. If running unbuffered, your program will always have to wait, until the new line is printed on screen. If the console waits for screen redraw and screen is redrawn at 60Hz, you've got your 16ms/line and about 60 lines per second.
Running your code without inner loop inside IntelliJ Idea, I get about 140.000 lines per second (and Idea warns me, that it is not displaying every line, as my output is too fast).
With the inner loop, I get about 800-900 lines. That happens because the process may be scheduled out of cpu, or blocked because of something else, like swapping. (If I simplify a lot, usually desktop OSes schedule in 1ms granularity.)

how to benchmark an infinite loop java nio watchservice program

I have a infinite polling loop using java.nio.file.WatchService looking for new files .Inside the loop i have fixed thread pool executor service to process files concurrently.
As the polling service keeps running, how can i benchmark the time taken for a batch of say 10/n files to process.i am able to time each file in the runnable class but how can get the batch processing time ?
Something like this should work:
// inside the listener for the WatchService
final MyTimer t = new MyTimer(); // takes current time, initialized to 0 tasks
for (Change c : allChanges) {
t.incrementTaskCount(); // synchronized
launchConcurrentProcess(c, t);
}
// inside your processor, after processing a change
t.decrementTaskCount(); // also synchronized
// inside MyTimer
public void synchronized decrementTaskCount() {
totalTasks --;
// depending on your benchmarking needs, you can do different things here
// I am printing max time only (= end of last), but min/max/avg may also be nice
if (totalTasks == 0) {
System.err.println("The time spent on this batch was "
+ System.currentTimeMillis() - initialTime);
}
}

How to run a Java program for a specific amount of time?

I want to run my program on a list of files. But a few files take much longer than expected time. So I want to kill the thread/process after the timeout period, and run the program on next file. Is there any easy way to do it? I'll be running only one thread at a time.
Edit1:
I am sorry I couldn't make it clear earlier. Here is the for loop code.
for (File file : files)
{
//Perform operations.
}
So a file is Java program file which can contain many methods. If the number of methods are less, my analysis works fine. If there are many say 20 methods, it keeps executing and analyzing them for a few hours. So in the latter case, I would like to finish that execution and go for the next java file.
And I don't have any constraint of single threading. If multi-threading works, it's still good for me. Thanks.
These kinds of things are usually done multi-threaded. For an example, see How to timeout a thread .
As you commented though, you are looking for a single-threaded solution. That is best done by periodically checking if the timeout expired yet. Some thread will have to do the checking, and since you requested it to have only one thread, the checking will have to be somewhere halfway in the code.
Let's say that the majority of the time spent is in a while-loop that reads the file line-by-line. You could do something like this:
long start = System.nanoTime();
while((line = br.readLine()) != null) {
if(System.nanoTime() - start > 600E9) { //More than 10 minutes past the start.
throw new Exception("Timeout!");
}
... //Process the line.
}
Just as a quick example of how you would do this using multi-threading:
First we make a Runnable for processing the File
class ProcessFile implements Runnable {
File file;
public ProcessFile(File file){
this.file = file;
}
public void run(){
//process the file here
}
}
Next we actually execute that class as a thread:
class FilesProcessor {
public void processFiles(){
//I guess you get the files somewhere in here
ExecutorService executor = Executors.newSingleThreadExecutor();
ProcessFile process;
Future future;
for (File file : files) {
process = new ProcessFile(file);
future = executor.submit(process);
try {
future.get(10, TimeUnit.MINUTES);
System.out.println("completed file");
} catch (TimeoutException e) {
System.out.println("file processing timed out");
}
}
executor.shutdownNow();
}
}
So we iterate through each file and process it. If it takes longer than 10 minutes, we get a timeout exception and the thread dies. Easy as pie.
I think you have a while or for loop for processing these files what about reading a timer each loop turn.
You can measure how long you are processing data with:
while(....){
long start = System.currentTimeMillis();
// ... the code being measured ...
long elapsedTime = System.currentTimeMillis() - start;
}
Or maybe starting chronometer before loop i don't know
EDIT :
So if you have one loop turn by file you have to put somme time measure at some specific point in your code like said darius.
For example :
for each file
start = System.currentTimeMillis();
//do some treatment
elapsedTime = System.currentTimeMillis() - start;
// do a more tratment
elapsedTime = System.currentTimeMillis() - start;

Categories

Resources