3

When I checked this Question couldn't believe it so I tested and seems to be true. Declaration inside loops seems to be faster than declaration outside loops. Can some one explain why is that?

Here's my testing code:

public class CycleTest {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        long iterations = 1000000;
        warmUp(iterations);
        System.out.println("Cycle1");
        double individualTime = getAverageTimePerIterationc1(iterations);
        iterations = 1000;
        double totalTime = getTotalTimec1(iterations);

        System.out.println("ns/iteration: " + individualTime);
        System.out.println("Total time for " + iterations + " runs: " + totalTime);

        System.out.println("Cycle2");
        iterations = 1000000;
        double individualTime1 = getAverageTimePerIterationc2(iterations);
        iterations = 1000;
        double totalTime1 = getTotalTimec2(iterations);

        System.out.println("ns/iteration: " + individualTime1);
        System.out.println("Total time for " + iterations + " runs: " + totalTime1);

    }

    public static void warmUp(long iterations) {
        System.out.println("Starting warmup");
        for (int i = 0; i < iterations; i++) {
            runCycles();
            runCycles1();
        }
    }

    public static double getAverageTimePerIterationc1(long iterations) {
        // test
        System.out.println("Starting individual time test");
        long timeTaken = 0;
        for (int i = 0; i < iterations; i++) {
            long startTime = System.nanoTime();
            runCycles();
            timeTaken += System.nanoTime() - startTime;
        }
        return (double) timeTaken / iterations;
    }

    public static long getTotalTimec1(long iterations) {
        // test
        System.out.println("Starting total time test");
        long timeTaken = 0;
        for (int i = 0; i < iterations; i++) {
            long startTime = System.nanoTime();
            runCycles();
            timeTaken += System.nanoTime() - startTime;
        }
        return timeTaken;
    }

    public static double getAverageTimePerIterationc2(long iterations) {
        // test
        System.out.println("Starting individual time test");
        long timeTaken = 0;
        for (int i = 0; i < iterations; i++) {
            long startTime = System.nanoTime();
            runCycles1();
            timeTaken += System.nanoTime() - startTime;
        }
        return (double) timeTaken / iterations;
    }

    public static long getTotalTimec2(long iterations) {
        // test
        System.out.println("Starting total time test");
        long timeTaken = 0;
        for (int i = 0; i < iterations; i++) {
            long startTime = System.nanoTime();
            runCycles1();
            timeTaken += System.nanoTime() - startTime;
        }
        return timeTaken;
    }

    private static void runCycles() {
        double intermediateResult;
        for (int i = 0; i < 1000; i++) {
            intermediateResult = i;
            intermediateResult += 1;
        }
    }

    private static void runCycles1() {
        for (int i = 0; i < 1000; i++) {
            double intermediateResult = i;
            intermediateResult += 1;
        }
    }
}

Extra new info: I have run it on JDK 1.6.0_27 on a Windows machine.

Community
  • 1
  • 1
Ruslan López
  • 4,433
  • 2
  • 26
  • 37
  • Is the line `System.out.println(intermediateResult);` commented out when you do the test? – Paul Boddington Oct 27 '15 at 00:26
  • 2
    That code looks awfully familiar ;) http://codereview.stackexchange.com/a/108562/87743 – Zymus Oct 27 '15 at 00:48
  • @Paul Boddington Yes it is to avoid excesive output. – Ruslan López Oct 27 '15 at 00:59
  • @Zymus yes... perhaps we can get some feedback about it too. Wouldn't it be great? :P – Ruslan López Oct 27 '15 at 01:00
  • @RuslanLópezCarro The trouble is that if you comment out that line, the assigned value isn't used, so it may be possible to optimise the loop away completely (I don't claim to understand these things). If I make it so that I actually do something with the value (e.g. `sum += intermediateResult;`) I get similar times for both versions. However, when I run Andreas's exact code using `jdk1.8.0_25` I don't get his results. For me, only `runCycles1` goes to `0` (i.e. declaring **outside** the loop is faster). I've tried it several times, and it's similar each time. – Paul Boddington Oct 27 '15 at 01:08
  • Thank you @PaulBoddington I've changed the code with an extra operation, hope you can perceive the runtime difference now that it ( hopefully ) generates different bytecode. – Ruslan López Oct 27 '15 at 01:21

1 Answers1

6

They generate the same code. These two methods:

private static void runCycles1() {
    double intermediateResult;
    for (int i = 0; i < 1000; i++) {
        intermediateResult = i;
    }
}
private static void runCycles2() {
    for (int i = 0; i < 1000; i++) {
        double intermediateResult = i;
    }
}

Generates this bytecode in Java 8 (jdk1.8.0_51):

runCycles1()                runCycles2()
Code:                       Code:
   0: iconst_0                 0: iconst_0                i = 0
   1: istore_2                 1: istore_0
   2: goto          11         2: goto          11        goto 11

   5: iload_2                  5: iload_0                 intermediateResult = (double)i
   6: i2d                      6: i2d
   7: dstore_0                 7: dstore_1
   8: iinc          2, 1       8: iinc          0, 1      i++

  11: iload_2                 11: iload_0                 if (i < 1000) goto 5
  12: sipush        1000      12: sipush        1000
  15: if_icmplt     5         15: if_icmplt     5
  18: return                  18: return                  return

The actual declaration doesn't generate any code, so I'd be surprised if you see a difference in performance.

So tested it:

for (int j = 0; j < 10; j++) {
    long t1 = System.nanoTime();
    for (int i = 0; i < 1000_000_000; i++)
        runCycles1();
    long t2 = System.nanoTime();
    for (int i = 0; i < 1000_000_000; i++)
        runCycles2();
    long t3 = System.nanoTime();
    System.out.printf("%d  %d%n", t2 - t1, t3 - t2);
}

And got:

4250095  2020120
4067898  0
3904236  0
0  0
0  0
0  0
0  0
0  0
0  0
0  0

They both eventually compile to nothing!!!

Andreas
  • 154,647
  • 11
  • 152
  • 247