Reputation: 18991
I am taking a course in Algorithms and Algorithms analyzing. And I want to know how much a simple operation +
,-
,/
,*
can take on my computer. So I write a simple stop watch as follow:
public class NanosecondsStopWatch implements StopWatch {
private PrintStream stream;
public NanosecondsStopWatch(PrintStream stream) {
this.stream = stream;
}
@Override
public void timeAndPrint(Action action) {
long start = System.nanoTime();
action.doAction();
long end = System.nanoTime();
stream.println(end-start);
}
}
public class TestingOperationsTime {
public static void main(String[] strings) {
StopWatch watch = new NanosecondsStopWatch(System.out);
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2*2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2/2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2-2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2+2;
}
});
}
}
The results are as follow
2529
454
355
335
However if I change the order of the operations say like this:
public class TestingOperationsTime {
public static void main(String[] strings) {
StopWatch watch = new NanosecondsStopWatch(System.out);
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2-2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2*2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2/2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2+2;
}
});
}
}
The result is still the nearly the same:
2494
332
309
326
How can you explain this behavior ?
Upvotes: 3
Views: 1493
Reputation: 3244
2 main problems (1) you are calling a function, which consume a lot of resouces. (2) you execute it only once. If you run the statement directly, or run it MANY times you will see the execution time is very small. Below result is time=0ns
public class PerfTest {
public static void main(String[] args) {
long t1 = System.nanoTime();
int i = 2 * 2;
long t2 = System.nanoTime();
System.out.printf("time=%dns", t2 -t1);
}
}
Upvotes: 0
Reputation: 3230
This is not a simple thing. In short, Java isn't the right Language to measure things.
Java is a Just-In-Time compiled Language. This means that the code you write runs within a "virtual machine", and it might be either fully interpreted, fully compiled, or partly compiled. That's why, in general, the first run is always slower: it's always interpreted. Only later can the VM decide to compile it and swap the compiled code with the interpreted procedure.
Moreover, there is a significant overhead in calling system procedures from the JVM, which somehow alters your measurements. So yes, you can make measurements, if you first make a "warm-up" loop, to make the VM understand that a given method must be compiled, and then discard the first result. But the results don't exactly measure your CPU's performance. You should use C or assembler for that, and even in that case, you must deal with context switches and OS management, which alter your results.
PS: And yes, I didn't mention it, because there were already 4 other answers about that, but the Java compiler isn't so stupid, and it will evaluate constant operation at compile time. i=2*2
is compiled to i=4
, so you're not measuring multiplication time, but only assignment time.
Upvotes: 1
Reputation: 5133
The compiler evaluates Constant expressions at compile time, you should make this a method that receives parameters.
Secondly, the system call to the watch takes more then a few a nano seconds, so this check will never be percice, what you are actually getting is how much time it takes for java to get the time.
Upvotes: 2
Reputation: 83547
There are many factors that influence the amount of system time used by your code. For example, if the computer does a context switch while your code is running, the time you get includes time spent running another program.
To mitigate this, you could run the timer many times, say thousands or millions, and take an average.
Also, as @rgettman points out, the compiler will most likely optimize these calculations because they are performed on constant values. That means you are only timing the overhead of calling a method and printing output and not the time to perform the calculation.
Upvotes: 5
Reputation: 3281
There will always be differences, because there are other processes running on your computer and depending on OS some processes will take priority over others. You cannot really predict exactly how many miliseconds does single operation take. It also depends on how fast CPU you have in your computer.
Upvotes: 2