Java: Calculate how long sorting an array takes - java

I have some code that generates 1000 numbers in an array and then sorts them:
import java.util.Arrays;
import java.util.Random;
public class OppgA {
public static void main(String[] args) {
int[] anArray;
anArray = new int[1000];
Random generator = new Random();
for(int i=0; i<1000; i++){
anArray[i] = (generator.nextInt(1000)+1);
}
Arrays.sort(anArray);
System.out.println(Arrays.toString(anArray));
}
}
Now I'm asked to calculate and print the time it took to sort the array. Any clues how I can do this? I really couldn't find much by searching that could help me out in my case.
Thanks!

You can call (and store the result of) System.nanoTime() before and after the call to Arrays.sort()- the difference is the time spent in nanoseconds. That method is preferred over System.currentTimeMillis to calculate durations.
long start = System.nanoTime();
Arrays.sort(anArray);
long end = System.nanoTime();
long timeInMillis = TimeUnit.MILLISECONDS.convert(end - start, TimeUnit.NANOSECONDS);
System.out.println("Time spend in ms: " + timeInMillis);
But note that the result of your measurement will probably vary widely if you run the program several times. To get a more precise calculation would be more involved - see for example: How do I write a correct micro-benchmark in Java?.

Before sorting, declare a long which corresponds to the time before you start the sorting:
long timeStarted = System.currentTimeMillis();
//your sorting here.
//after sorting
System.out.println("Sorting last for:" + (System.currentTimeMillis() - timeStarted));
The result will return the milli seconds equivalent of your sorting.
As assylias commented you can also use System.nanoTime() if you prefer precise measurements of elapsed time.

Proper microbenchmarking is done using a ready-made tool for that purpose, like Google Caliper or Oracle jmh. However, if you want a poor-man's edition, follow at least these points:
measure with System.nanoTime() (as explained elsewhere). Do not trust small numbers: if you get timings such as 10 microseconds, you are measuring a too short timespan. Enlarge the array to get at least into the milliseconds;
repeat the sorting process many times (10, 100 perhaps) and display the timing of each attempt. You are expected to see a marked drop in the time after the first few runs, but after that the timings should stabilize. If you still observe wild variation, you know something's amiss;
to avoid garbage collection issues, reuse the same array, but re-fill it with new random data each time.

long beforeTime = System.currentTimeMillis();
// Your Code
long afterTime = System.currentTimeMillis();
long diffInMilliSeconds = afterTime- beforeTime;

before starting the calculation or exactly after generating the array you can use System#currentTimeMillis() to get the exact time and do the same exactly after completion of sorting and then find the difference.

do it this way :
long start = System.currentTimeMillis();
...
your sorting code
...
long end = System.currentTimeMillis();
long timeInMillis = end - start;
Hope that helps.

import java.util.Arrays;
import java.util.Random;
public class OppgA {
public static void main(String[] args) {
int[] anArray;
anArray = new int[1000];
Random generator = new Random();
for(int i=0; i<1000; i++){
anArray[i] = (generator.nextInt(1000)+1);
}
Date before = new Date();
Date after;
Arrays.sort(anArray);
after = new Date();
System.out.println(after.getTime()-before.getTime());
System.out.println(Arrays.toString(anArray));
}
}

This is not an ideal way. But this will work
long startingTime=System.currentTimeMillis();
Arrays.sort(anArray);
long endTime=System.currentTimeMillis();
System.out.println("Sorting time: "+(endTime-startingTime)+"ms");
Following can be the best way
long startingTime=System.nanoTime();
Arrays.sort(anArray);
long endTime=System.nanoTime();
System.out.println("Sorting time: "+(endTime-startingTime)+"ns");

In short, you can either extract our code to a method and than calculate the difference between the timestamps of start and end of that method or you can just run it in a profiler or an IDE and it will print the execution time
Ideally, you should not mix your business logic (array sorting in this case) with 'metrics' stuff.If you do need to measure execution time within the app, you can try to use AOP for that
Please refer to this post , which describes possible solutions in very detail

Related

efficiency of loop through a 2d array horizontally or vertically

I read an article in stackoverflow posted 4 years ago, see here:
Fastest way to loop through a 2d array?
Almost every answer agreed that scan horizontally will faster. I wrote a short Java program to check this, it turned out not the case. I choose 400x400 matrix. The time for scan horizontally is 6 and the time for scan vertically is 3. I checked other sizes of matrix. It also turned out scan vertically is faster. Do I miss something or is it indeed the case?
public class Test {
public static void main(String[] args) {
int row=Integer.parseInt(args[0]);
int column=Integer.parseInt(args[1]);
int[][] bigarray=new int[row][column];
long startTime = System.currentTimeMillis();
for(int i=0;i<row;i++)
for(int j=0;j<column;j++)
bigarray[i][j]=Math.abs(i-j)-Math.abs(i-j);
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("scan horizentally time is: ");
System.out.println(totalTime);
int[][] bigarray1=new int[row][column];
long startTime1 = System.currentTimeMillis();
for(int j=0;j<column;j++)
for(int i=0;i<row;i++)
bigarray1[i][j]=Math.abs(i-j)-Math.abs(i-j);
long endTime1 = System.currentTimeMillis();
long totalTime1 = endTime1 - startTime1;
System.out.println("scan vertically time is: ");
System.out.println(totalTime1);
}
}
For the horizontal version, you could optimize the code:
for(int i=0;i<row;i++)
int[] rowArray = bigarray[i];
for(int j=0;j<column;j++)
rowArray[j]=Math.abs(i-j)-Math.abs(i-j);
I wouldn't be surprised if the first test is always slower with your test setup. Java takes a lot of warmup time... A better test setup might be to have two separate programs, and to take a few warmup loops before taking the time...

Strange code timing behavior in Java

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

Comparing methods speed performance using nanotime in Java

I would like to compare the speed performance (if there were any) from the two readDataMethod() as I illustrate below.
private void readDataMethod1(List<Integer> numbers) {
final long startTime = System.nanoTime();
for (int i = 0; i < numbers.size(); i++) {
numbers.get(i);
}
final long endTime = System.nanoTime();
System.out.println("method 1 : " + (endTime - startTime));
}
private void readDataMethod2(List<Integer> numbers) {
final long startTime = System.nanoTime();
int i = numbers.size();
while (i-- > 0) {
numbers.get(i);
}
final long endTime = System.nanoTime();
System.out.println("method 2 : " + (endTime - startTime));
}
Most of the time the result I get shows that method 2 has "lower" value.
Run readDataMethod1 readDataMethod2
1 636331 468876
2 638256 479269
3 637485 515455
4 716786 420756
Does this test prove that the readDataMethod2 is faster than the earlier one ?
Does this test prove that the readDataMethod2 is faster than the earlier one ?
You are on the right track in that you're measuring comparative performance, rather than making assumptions.
However, there are lots of potential issues to be aware of when writing micro-benchmarks in Java. I would recommend that you read
How do I write a correct micro-benchmark in Java?
In the first one, you are calling numbers.size() for each iteration.
Try storing it in a variable, and check again.
The reason because of which the second version runs faster is because you are calling numbers.size() on each iteration. Replacing it by storing in a number would make it almost the same as the first one.
Does this test prove that the readDataMethod2 is faster than the earlier one ?
As #aix says, you are on the right track. However, there are a couple of specific issues with your methodology:
It doesn't look like you are "warming up" the JVM. Therefore it is conceivable that your figures could be distorted by startup effects (JIT compilation) or that none of the code has been JIT compiled.
I'd also argue that your runs are doing too little work. A 500000 nanoseconds, is 0.0005 seconds, and that's not much work. The risk is that "other things" external to your application could be introducing noise into the measurements. I'd have more confidence in runs that take tens of seconds.

Wrong time of method execution

I want to test the time of adding and getting item in simple and generic hashmap:
public void TestHashGeneric(){
Map hashsimple = new HashMap();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
hashsimple.put("key"+i, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" );
}
for (int i = 0; i < 100000; i++) {
String ret =(String)hashsimple.get("key"+i);
}
long endTime =System.currentTimeMillis();
System.out.println("Hash Time " + (endTime - startTime) + " millisec");
Map<String,String> hm = new HashMap<String,String>();
startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
hm.put("key"+i, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" );
}
for (int i = 0; i < 100000; i++) {
String ret = hm.get("key"+i);
}
endTime = System.currentTimeMillis();
System.out.println("Hash generic Time " + (endTime - startTime) + " millisec");
}
The problem is that I get different time if I change places between hashmap's code section!
if i put the loops (with the time print ofcourse) of generic below the simple I get better time for generic and if i put simple below the generic I get better time for simple!
Same happens if I use different methods for this.
The JIT will compile and optimise your program while it is running, so the 2nd run will always be faster.
You should make the following modifications:
Run both tests untimed first, then re-run them timed so that you don't get affected by the JIT.
You should use System.nanoTime() as this is more accurate for timing (you should never get a diff of 0).
You should also test against some empty methods, as you are also timing the string concatenation operation in each loop.
Also note that in Java generic types are erased, so there should be no runtime difference at all.
The Java Runtime is pretty sophistocated - it does some learning/optimisation while it's running. You might be able to get the test you want by "warming up" the JVM first. Try calling TestHashGeneric() twice and see what the second set of results gives you.
You've also got twice as much stuff in memory on the second run. There's all sorts of variables that can affect this test.
This is not the correct way to perform micro-benchmarks as it is very involved (Why?). I suggest you use Caliper framework for this.
When you have a single loop which reaches the compile threshold (about 10K) the whole method is compiled. This can make either the first loop appear faster (as it is optimised correctly as the second loop has no counter information) or the second loop appear after (as its compiled before it is even started)
This simplest way to fix this is to place each test in its own method and they will be compiled and optimised independently. (The order can still matter but is less important) I would still suggest running the test a number of times to see how the results vary.

adding run time on my java program

what is the correct code to calculating time in Java with
public static int getGcd( int a, int b, int temp) format?
A simple solution:
First, Grab and store the time before you start the piece of code you want the run time for:
long start =System.currentTimeMillis();
After the code that you are tracking grab the current time and subtract it from your starting point to get the total time elapsed:
System.out.println(System.currentTimeMillis() - start);
If it runs relatively fast and you're trying to get an average time by running it on a bunch of random inputs, use:
long totalTime = 0;
long start = System.nanoTime();
for(int i=0;i<n;i++){
//Generate a and b
getGcd(a, b);
}
long end = System.nanoTime();
totalTime = end - start;
start = System.nanoTime();
for (int i=0;i<n;i++){
//Generate a and b
}
end = System.nanoTime();
totalTime -= end - start;
return totalTime / n;
This gives you your average time in nanoseconds.
Finding the average running time of GCD is a very interesting and complex problem. In the worst case, the inputs have a ratio which is close to the golden mean (such as consecutive Fibonacci numbers) and then the running time is O(log n). But it's still possible to have extremely large inputs and end up with essentially constant time. I'd be curious to know your results.

Categories