I'm trying to measure the execution time of a loop, which is a simple Add Matrices.
here's my code:
//get integers m and n from user before this.
long start,end,time;
int[][] a = new int[m][n];
int[][] b = new int[m][n];
int[][] c= new int[m][n];
start = getUserTime();
for(int i = 0;i < m;i++)
{
for(int j = 0;j < n;j++)
{
c[i][j] = a[i][j]+b[i][j];
}
}
end = getUserTime();
time = end - start;
/** Get user time in nanoseconds. */
public long getUserTime() {
ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
return bean.isCurrentThreadCpuTimeSupported( ) ?
bean.getCurrentThreadUserTime() : 0L;
}
the problem is, sometimes it returns 0, for example when I input 1000 as m and n. which means I have two 1000x1000 matrices being added. sometimes it returns 0 and sometimes 15ms (both keep getting repeated).
I don't know whether to believe 15ms or 0. and there is a big difference between them.
I know the accuracy is OS dependent and not really nanoseconds accurate but 15miliseconds is way off to be an accuracy problem.
EDIT: the very goal of this code was to measure CPU performance on the loop. so if possible I want the effect of Compiler optimization and OS context switching etc to be minimal.
many thanks.
You should use System.nanoTime(). (API Here)
From the documentation:
This method can only be used to measure elapsed time and is not
related to any other notion of system or wall-clock time. The value
returned represents nanoseconds since some fixed but arbitrary origin
time (perhaps in the future, so values may be negative). The same
origin is used by all invocations of this method in an instance of a
Java virtual machine; other virtual machine instances are likely to
use a different origin.
So the nanoTime() is fine for use to measure your execution time because the measurement will always be the same and it will use nanoseconds.
Set the start time to the current nano time.
start = System.nanoTime();
At the end of the loop set the end time to the current nano time
end = System.nanoTime();
To find the difference, which is the time it took to execute, just subtract like you do.
To make it easy, you can just change getUserTime() to return System.nano()
Example:
//get integers m and n from user before this.
long start,end,time;
int[][] a = new int[m][n];
int[][] b = new int[m][n];
int[][] c= new int[m][n];
start = getUserTime();
for(int i = 0;i < m;i++)
{
for(int j = 0;j < n;j++)
{
c[i][j] = a[i][j]+b[i][j];
}
}
end = getUserTime();
// You could use Math.abs() here to handle the situation where
// the values could be negative
time = end - start;
/** Get user time in nanoseconds. */
public long getUserTime() {
return System.nanoTime()
}
Related
I have 2 pieces of code and first part is here
int count = myArrayList.size();
for (int a =0; a< count; a++) {
//any calculation
}
Second part of the code is
for (int a =0; a< myArrayList.size(); a++) {
//any calculation
}
in both piece I am iterating over myArrayList (this is ArrayList) size but in first part I am calculating size then iterating it means the method size is being called only once but on the other hand in second part whenever it iterates it calculates the size first then then check for size in less than or not.Isn't it long process ?I have seen in many examples in many places (which calculate size on every iteration).
My questions:
Isn't it long process? (talking about second part)
what is best practice first or second?
which is efficient way to perform iteration?
myArrayList.size() how this size method works or calculates the size?
EDITION:
For testing the same thing I wrote programs and calculated the time the code is
ArrayList<Integer> myArrayList = new ArrayList<>();
for (int a =0; a<1000; a++) {
myArrayList.add(a);
}
long startTime = System.nanoTime();
for (int a =0; a< myArrayList.size(); a++) {
//any calculation
}
long lastTime = System.nanoTime();
long result = lastTime - startTime;
and the result is = 34490 nano seconds
on the other hand
ArrayList<Integer> myArrayList = new ArrayList<>();
for (int a =0; a<1000; a++) {
myArrayList.add(a);
}
long startTIme = System.nanoTime();
int count = myArrayList.size();
for (int a =0; a< count; a++) {
}
long endTime = System.nanoTime();
long result = endTime - startTIme;
and the result is = 11394 nano seconds
here when calling size() method in every iteration taking much time then without calling it every call.Is this the right way to check the time calculation?
No. The call is not a "long running" process, the JVM can make function calls quickly.
Either is acceptable. Prefer the one that's easier to read. Adding a local reference with a meaningful name can make something easier to read.
You might prefer the for-each loop, but for readability1. There is no appreciable efficiency difference in your options (or with the for-each).
The ArrayList implementation keeps an internal count (in the OpenJDK implementation, and probably others, that is size) and manages the internal array that backs the List.
1See also The Developer Insight Series, Part 1: Write Dumb Code
This is just a hypothetical question, but could be a way to get around an issue I have been having.
Imagine you want to be able to time a calculation function based not on the answer, but on the time it takes to calculating. So instead of finding out what a + b is, you wish to continue perform some calculation while time < x seconds.
Look at this pseudo code:
public static void performCalculationsForTime(int seconds)
{
// Get start time
int millisStart = System.currentTimeMillis();
// Perform calculation to find the 1000th digit of PI
// Check if the given amount of seconds have passed since millisStart
// If number of seconds have not passed, redo the 1000th PI digit calculation
// At this point the time has passed, return the function.
}
Now I know that I am horrible, despicable person for using precious CPU cycles to simple get time to pass, but what I am wondering is:
A) Is this possible and would JVM start complaining about non-responsiveness?
B) If it is possible, what calculations would be best to try to perform?
Update - Answer:
Based on the answers and comments, the answer seems to be that "Yes, this is possible. But only if it is not done in Android main UI thread, because the user's GUI will be become unresponsive and will throw an ANR after 5 seconds."
A) Is this possible and would JVM start complaining about non-responsiveness?
It is possible, and if you run it in the background, neither JVM nor Dalvik will complain.
B) If it is possible, what calculations would be best to try to perform?
If the objective is to just run any calculation for x seconds, just keep adding 1 to a sum until the required time has reached. Off the top of my head, something like:
public static void performCalculationsForTime(int seconds)
{
// Get start time
int secondsStart = System.currentTimeMillis()/1000;
int requiredEndTime = millisStart + seconds;
float sum = 0;
while(secondsStart != requiredEndTime) {
sum = sum + 0.1;
secondsStart = System.currentTimeMillis()/1000;
}
}
You can and JVM won't complain if your code is not part of some complex system that actually tracks thread execution time.
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis() - startTime < 100000) {
// do something
}
Or even a for loop that checks time only every 1000 cycles.
for (int i = 0; ;i++) {
if (i % 1000 == 0 && System.currentTimeMillis() - startTime < 100000)
break;
// do something
}
As for your second question, the answer is probably calculating some value that can always be improved upon, like your PI digits example.
I make a benchmark like this :
for (int i = 0; i < 1000 * 1000; ++i) {
long var = System.nanoTime();
}
it takes 41 ms in my computer with jdk6.0
the follow code only costs 1 ms!!!
for (int i = 0; i < 1000 * 1000; ++i) {
System.nanoTime();
}
I think may be that time is costed by long var , so I make a test like this :
for (int i = 0; i < 1000 * 1000; ++i) {
long var = i;
}
it only costs 1 ms!!!
So,Why the first code block is so slow?
I'm a Chinese. Sorry for my poor English!
It really depends on how you run your benchmark. You most likely get <1ms runs because the JVM is not really running your code: it has determined that the code is not used and skips it:
for (int i = 0; i < 1000 * 1000; ++i) {
long var = i;
}
is equivalent to
//for (int i = 0; i < 1000 * 1000; ++i) {
// long var = i;
//}
and the JVM is probably running the second version.
You should read how to write a micro benchmark in Java or use a benchmarking library such as caliper.
It takes time for the JIT to detect your code doesn't do anything useful. The more complicated the code, the longer it takes (or it might not detect it at all)
In the second and third cases, it can replace the code with nothing (I suspect you can make it 100x longer and it won't run any longer)
Another possibility is you are running all three tests in the same method. When the first loop iterates more than 10,000 times, the whole method is compiled in the background such that when the second and third loops run they have been removed.
A simple way to test this is to change the order of the loops or better to place each loop in its own method to stop this.
In the following code:
long startingTime = System.nanoTime();
int max = (int) Math.pow(2, 19);
for(int i = 0; i < max; ){
i++;
}
long timePass = System.nanoTime() - startingTime;
System.out.println("Time pass " + timePass / 1000000F);
I am trying to calculate how much time it take to perform simple actions on my machine.
All the calculations up to the power of 19 increase the time it takes to run this code, but when I went above 19(up to max int value 31) I was amazed to discover that it have no effect on the time it takes.
It always shows 5 milliseconds on my machine!!!
How can this be?
You have just witnessed HotSpot optimizing your entire loop to oblivion. It's smart. You need to do some real action inside the loop. I recommend introducing an int accumulator var and doing some bitwise operations on it, and finally printing the result to ensure it's needed after the loop.
On the HotSpot JVM, -XX:CompileThreshold=10000 by default. This means a loop which iterates 10K times can trigger the whole method to be optimised. In your case you are timing how long it take to detect and compile (in the background) your method.
use another System.nanoTime() in the loop. no one can optimize this.
for(int i = 0; i < max; ){
i++;
dummy+=System.nanoTime();
}
dont forget to do:
System.out.println(dummy);
after the loop. ensures non-optimization
Look please at this code:
public static void main(String[] args) {
String[] array = new String[10000000];
Arrays.fill(array, "Test");
long startNoSize;
long finishNoSize;
long startSize;
long finishSize;
for (int called = 0; called < 6; called++) {
startNoSize = Calendar.getInstance().getTimeInMillis();
for (int i = 0; i < array.length; i++) {
array[i] = String.valueOf(i);
}
finishNoSize = Calendar.getInstance().getTimeInMillis();
System.out.println(finishNoSize - startNoSize);
}
System.out.println("Length saved");
int length = array.length;
for (int called = 0; called < 6; called++) {
startSize = Calendar.getInstance().getTimeInMillis();
for (int i = 0; i < length; i++) {
array[i] = String.valueOf(i);
}
finishSize = Calendar.getInstance().getTimeInMillis();
System.out.println(finishSize - startSize);
}
}
The execution result differs from run to run, but there can be observed a strange behavior:
6510
4604
8805
6070
5128
8961
Length saved
6117
5194
8814
6380
8893
3982
Generally, there are 3 result: 6 seconds, 4 seconds, 8 seconds and they iterates in the same order.
Who knows, why does it happen?
UPDATE
After some playing with -Xms and -Xmx Java VM option the next results was observed:
The minimum total memory size should be at least 1024m for this code, otherwise there will be an OutOfMemoryError. The -Xms option influences the time of execution of for block:
It flows between 10 seconds for -Xms16m and 4 seconds for -Xms256m.
The question is - why the initial available memory size affect each iteration and not only the first one ?
Thank you in advance.
Micro benchmarking in Java is not that trivial. A lot of things happen in the background when we run a java program; Garbage collection being a prime example. There also might be the case of a context switch from your Java process to another process. IMO, there is no definite explanation why there is a sequence in the seemingly random times generated.
This is not entirely unexpected. There are all sorts of factors that could be affecting your numbers.
See: How do I write a correct micro-benchmark in Java?