I have written the below code to observe the timing of a loop function. Surprisingly, It gives me different values for each run.
public static void main(String[] args) {
for (int attempt = 0; attempt < 10; attempt++) {
runloop();
}
}
public static void runloop() {
long sum = 0L;
long starttime = System.nanoTime();
for (int x = 0; x < 1000000; x++) {
sum += x;
}
long end = System.nanoTime();
System.out.println("Time taken:" + (end - starttime) / 1000L);
}
}
Observation :
Time taken:4062
Time taken:3122
Time taken:2707
Time taken:2445
Time taken:3575
Time taken:2823
Time taken:2228
Time taken:1816
Time taken:1839
Time taken:1811
I am not able to understand why there is such a difference in the timing.
What is the reason ?
It could be anything:
Other processes running on your computer limiting the time given to Java
Run of the garbage collector
Loop initialization time
...
Related
Consider the code snippets below and the time taken to execute them -
public static void main(String[] args) {
Long startTime = System.currentTimeMillis();
long sum = 0L;
for(int i = 0; i< Integer.MAX_VALUE; i++){
sum+=i;
}
Long timeDiff = (System.currentTimeMillis() - startTime) / 1000;
System.out.println("Time Difference : " + timeDiff + "secs");
}
Output -
Time Difference : 0secs
public static void main(String[] args) {
Long startTime = System.currentTimeMillis();
Long sum = 0L;
for(int i = 0; i< Integer.MAX_VALUE; i++){
sum+=i;
}
Long timeDiff = (System.currentTimeMillis() - startTime) / 1000;
System.out.println("Time Difference : " + timeDiff + "secs");
}
Output -
Time Difference : 8secs
public static void main(String[] args) {
Long startTime = System.currentTimeMillis();
Long sum = 0L;
for(Long i = 0L; i< Integer.MAX_VALUE; i++){
sum+=i;
}
Long timeDiff = (System.currentTimeMillis() - startTime) / 1000;
System.out.println("Time Difference : " + timeDiff + "secs");
}
Output -
Time Difference : 16secs
As per my understanding, it's happening because of every time object creation of Long Object, I am not sure how exactly this is happening. Tried looking into byte code didn't help much.
Help me understand how exactly things are internally happening?
Thanks in advance!
The "++" and "+=" operators are only defined for primitives.
Hence, when you apply them to a Long, an unboxing must take place before the operator is evaluated and then a boxing must take place to store the result.
The boxing probably costs more than the unboxing, since unboxing requires just a method call, while boxing requires object instantiation.
Each boxing involves the creation of a Long instance. Your loop has Integer.MAX_VALUE iterations, so the second loop creates over 2 billion Long objects (one for each sum+=i operation) while the third loop creates over 4 billion Long objects (one for each i++ operation and one for each sum+=i operation). These objects have to be instantiated and later garbage collected. That costs time.
Plausible causes:
- Too many object creations leading to GC activity at times.
- Too many boxing and unboxing of Wrapper to primitive and vice versa.
So I'm still fairly new to programming and I'm just wondering if I'm doing these benchmarks correctly. For queue I'm basically giving it a list filled with integers, and I would time how long it would take for it to find a number on the list. As for the HashMap it's basically the same idea, I would time how long it would take to get a number from the list. Also for both of them I would also time how long it would take for them to remove the contents of the list. Any help on this would be appreciated. Thank you!
// Create a queue, and test its performance
PriorityQueue<Integer> queue = new PriorityQueue <> (list);
System.out.println("Member test time for Priority Queue is " +
getTestTime(queue) + " milliseconds");
System.out.println("Remove element time for Priority Queue is " +
getRemoveTime(queue) + " milliseconds");
// Create a hash map, and test its performance
HashMap<Integer, Integer> newmap = new HashMap<Integer, Integer>();
for (int i = 0; i <N;i++) {
newmap.put(i, i);
}
System.out.println("Member test time for hash map is " +
getTestTime1(newmap) + " milliseconds");
System.out.println("Remove element time for hash map is " +
getRemoveTime1(newmap) + " milliseconds");
}
public static long getTestTime(Collection<Integer> c) {
long startTime = System.currentTimeMillis();
// Test if a number is in the collection
for (int i = 0; i < N; i++)
c.contains((int)(Math.random() * 2 * N));
return System.currentTimeMillis() - startTime;
}
public static long getTestTime1(HashMap<Integer,Integer> newmap) {
long startTime = System.currentTimeMillis();
// Test if a number is in the collection
for (int i = 0; i < N; i++)
newmap.containsKey((int)(Math.random() * 2 * N));
return System.currentTimeMillis() - startTime;
}
public static long getRemoveTime(Collection<Integer> c) {
long startTime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
c.remove(i);
return System.currentTimeMillis() - startTime;
}
public static long getRemoveTime1(HashMap<Integer,Integer> newmap) {
long startTime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
newmap.remove(i);
return System.currentTimeMillis() - startTime;
}
}
I have two suggestion. First, when doing benchmarking, do the bare minimum work immediately before and after the code you are evaluating. You don't want your benchmark activity to affect the result.
Second, System.currentTimeMillis() can, depending on the OS, only be accurate within 10 milliseconds. Better to use System.nanoTime(), which is accurate to perhaps 200 nanoseconds. Divide by 1_000_000 to get milliseconds.
Practically,
final long startNanos, endNanos;
startNanos = System.nanoTime();
// your code goes here
endNanos = System.nanoTime();
// display the results of the benchmark
This question already has answers here:
How do I write a correct micro-benchmark in Java?
(11 answers)
Closed 6 years ago.
I recently started learning java and I am kinda stumped by this---
the below program determines the speed of the for loop--
public class ForLoopExample {
public static void main(String[] args) {
long startTime = System.nanoTime();
for(int a = 0; a < 10; a++) {
System.out.println(a);
}
long endTime = System.nanoTime();
System.out.println("for loop timing = " + (endTime - startTime) + " ns");
System.out.println("loop completed");
}
}
and the output timing is:
for loop timing = 853716 ns
The program determining the speed of the while loop:
public class WhileLoopExample {
public static void main(String[] args) {
int a=0;
long startTime = System.nanoTime();
while(a < 10) {
System.out.println(a);
a++;
}
long endTime = System.nanoTime();
System.out.println("while loop timing = " + (endTime - startTime) + " ns");
}
}
while loop timing=928358 ns
Why does this happen a detailed explanation would be appreciated.
Rerun your test with more than ten iterations, but also run more iterations of those iterations, say 10000 in the inner loop and ten in the outer and average the results. They should be close.
The reason that there is variance is a result of the operating system and multi threading. The OS is managing many tasks other than your program and those may take a slightly higher priority than your program. This causes sight delays in your execution.
Having a much bigger sample size should decrease the variance in the results.
If I have a piece of code like so...
if(!hasRunMethod) {
runMethod();
hasRunMethod = true;
}
...and that code is being executed in a loop over and over, many times every second, even though the code inside is only called once, is this bad coding practice? If so, what should I do instead?
Quickly tested (on java version 1.8.0_05):
long start = System.nanoTime();
int run = 1_000_000;
for(int i = 0; i < run; ++i) {
if(alwaysTrue) {
}
}
long end = System.nanoTime();
end - start averages ~1,820,000 nano seconds.
this:
long start = System.nanoTime();
int run = 1_000_000;
for(int i = 0; i < run; ++i) {
// if(alwaysTrue) {
//
// }
}
long end = System.nanoTime();
end - start averages ~1,556,000 nano seconds.
as an added bonus:
long start = System.nanoTime();
int run = 1_000_000;
for(int i = 0; i < run; ++i) {
if(true) {
}
}
long end = System.nanoTime();
end - start averages ~1,542,000 nano seconds, same as commented out.
Conclusion
if(someBool){} inside a loop has some performance impact. But it's so negligible I find it hard to think of a bottleneck sensitive enough for it to matter.
My partner and I are attempting to program a LinkedList data structure. We have completed the data structure, and it functions properly with all required methods. We are required to perform a comparative test of the runtimes of our addFirst() method in our LinkedList class vs. the add(0, item) method of Java's ArrayList structure. The expected complexity of the addFirst() method for our LinkedList data structure is O(1) constant. This held true in our test. In timing the ArrayList add() method, we expected a complexity of O(N), but we again received a complexity of approximately O(1) constant. This appeared to be a strange discrepancy since we are utilizing Java's ArrayList. We thought there may be an issue in our timing structure, and we would be most appreciative if any one could help us identify our problem. Our Java code for the timing of both methods is listed below:
public class timingAnalysis {
public static void main(String[] args) {
//timeAddFirst();
timeAddArray();
}
public static void timeAddFirst()
{
long startTime, midTime, endTime;
long timesToLoop = 10000;
int inputSize = 20000;
MyLinkedList<Long> linkedList = new MyLinkedList<Long>();
for (; inputSize <= 1000000; inputSize = inputSize + 20000)
{
// Clear the collection so we can add new random
// values.
linkedList.clear();
// Let some time pass to stabilize the thread.
startTime = System.nanoTime();
while (System.nanoTime() - startTime < 1000000000)
{ }
// Start timing.
startTime = System.nanoTime();
for (long i = 0; i < timesToLoop; i++)
linkedList.addFirst(i);
midTime = System.nanoTime();
// Run an empty loop to capture the cost of running the loop.
for (long i = 0; i < timesToLoop; i++)
{} // empty block
endTime = System.nanoTime();
// Compute the time, subtract the cost of running the loop from
// the cost of running the loop and computing the removeAll method.
// Average it over the number of runs.
double averageTime = ((midTime - startTime) - (endTime - midTime)) / timesToLoop;
System.out.println(inputSize + " " + averageTime);
}
}
public static void timeAddArray()
{
long startTime, midTime, endTime;
long timesToLoop = 10000;
int inputSize = 20000;
ArrayList<Long> testList = new ArrayList<Long>();
for (; inputSize <= 1000000; inputSize = inputSize + 20000)
{
// Clear the collection so we can add new random
// values.
testList.clear();
// Let some time pass to stabilize the thread.
startTime = System.nanoTime();
while (System.nanoTime() - startTime < 1000000000)
{ }
// Start timing.
startTime = System.nanoTime();
for (long i = 0; i < timesToLoop; i++)
testList.add(0, i);
midTime = System.nanoTime();
// Run an empty loop to capture the cost of running the loop.
for (long i = 0; i < timesToLoop; i++)
{} // empty block
endTime = System.nanoTime();
// Compute the time, subtract the cost of running the loop from
// the cost of running the loop and computing the removeAll method.
// Average it over the number of runs.
double averageTime = ((midTime - startTime) - (endTime - midTime)) / timesToLoop;
System.out.println(inputSize + " " + averageTime);
}
}
}
You want to test for different inputSize, but you perform the operation to test timesToLoop times, which is constant. So of course, it takes the same time. You should use:
for (long i = 0; i < inputSize; i++)
testList.add(0, i);
As per my knowledge, Arraylist add operaion runs in O(1) time, so the results of your experiment are correct. I think the constant time for arrayList add method is amortized constant time.
As per java doc :
adding n elements require O(N) time so that is why the amortized constant time for adding.