lucene-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Steven A Rowe" <sar...@syr.edu>
Subject RE: [jira] Created: (LUCENE-1257) Port to Java5
Date Tue, 08 Apr 2008 22:57:25 GMT
On 04/04/2008 at 4:40 AM, Toke Eskildsen wrote:
> On Wed, 2008-04-02 at 09:30 -0400, Mark Miller wrote:
> > > - replacement of indexed for loops with for each constructs
> > 
> > Is this always the best idea? Doesn't the for loop construct make an
> > iterator, which can be much slower than an indexed for loop?
> 
> Only in the case of iterations over collections. For arrays, the foreach
> is syntactic sugar for indexed for-loop.
> http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.14.2

I don't think this is actually true.  The text at the above-linked page simply says that for-each
over an array "means the same as" an indexed loop over the same array.  "Syntactic sugar",
OTOH, implies that the resulting opcode is exactly the same.  When I look at the byte code
(using javap) for the comparison test I include below, I can see that the indexed and for-each
loops do not generate the same byte code.

I constructed a simple program to compare the runtime length of the two loop control mechanisms,
while varying the size of the array.  The test program takes command line parameters to control
which loop control mechanism to use, the size of the array (#elems), and the number of times
to execute the loop (#iters).  I used a Bash shell script to invoke the test program.

Summary of the results: over int[] arrays, indexed loops are faster on arrays with fewer than
about a million elements.  The fewer the elements, the faster indexed loops are relative to
for-each loops.  This could be explained by a higher one-time setup cost for the for-each
loop - above a certain array size, the for-each setup cost is lost in the noise.  It should
be noted, however, that this one-time setup cost is quite small, and might be worth the increased
code clarity.

Here are the results for three different platforms:

  - Best of five iterations for each combination
  - All using the -server JVM option
  - Holding constant #iters * #elems = 10^10
  - Rounding the reported real time to the nearest tenth of a second
  - "% Slower" = 100 * ((For-each - Indexed) / Indexed)

Platform #1: Windows XP SP2; Intel Core 2 duo 6600@2.4GHz; Java 1.5.0_13

#iters  #elems  For-each  Indexed  % Slower
------  ------  --------  -------  --------
  10^9    10^1     22.3s    13.8s       62%
  10^8    10^2     16.0s    13.6s       18%
  10^6    10^4     14.8s    13.0s       14%
  10^4    10^6     12.9s    12.9s        0%
  10^3    10^7     13.4s    13.3s        1%

Platform #2: Debian Linux, 2.6.21.7 kernel; Intel Xeon 5060@3.2GHz; Java 1.5.0_14

#iters  #elems  For-each  Indexed  % Slower
------  ------  --------  -------  --------
  10^9    10^1     33.6s    14.2s      137%
  10^8    10^2     20.4s    13.9s       47%
  10^6    10^4     19.0s    12.7s       50%
  10^4    10^6     12.7s    12.8s       -1%
  10^3    10^7     13.2s    13.2s        0%

Platform #3: Debian Linux, 2.6.21.7 kernel; Intel Xeon PIII@866MHz; Java 1.5.0_10

#iters  #elems  For-each  Indexed  % Slower
------  ------  --------  -------  --------
  10^9    10^1    102.7s    73.6s       40%    
  10^8    10^2    107.8s    60.0s       80%
  10^6    10^4    105.2s    58.6s       80%
  10^4    10^6     58.8s    53.0s       11%
  10^3    10^7     60.0s    54.1s       11%


----- ForEachTest.java follows -----

import java.util.Date;
import java.util.Random;

/**
 * This is meant to be called from a shell script that varies the loop style,
 * the number of iterations over the loop, and the number of elements in the
 * array over which the loop iterates, e.g.:
 * 
 *     cmd="java -server -cp . ForEachTest"
 *     for elems in 10 100 10000 1000000 10000000 ; do
 *         iters=$((10000000000/${elems}))
 *         for run in 1 2 3 4 5 ; do
 *             time $cmd --indexed --arraysize $elems --iterations $iters
 *             time $cmd --foreach --arraysize $elems --iterations $iters
 *         done
 *     done
 *
 */
public class ForEachTest {
  static String NL = System.getProperty("line.separator");
  static String usage
    = "Usage: java -server -cp . ForEachTest [ --indexed | --foreach ]"
      + NL + "\t--iterations <num-iterations>  --arraysize <array-size>";
    
  public static void main(String[] args) {
    boolean useIndexedLoop = false;
    int size = 0;
    int iterations = 0;
    try {
      for (int argnum = 0 ; argnum < args.length ; ++argnum) {
        if (args[argnum].equals("--indexed")) {
          useIndexedLoop = true;
        } else if (args[argnum].equals("--foreach")) {
          useIndexedLoop = false;
        } else if (args[argnum].equals("--iterations")) {
          iterations = Integer.parseInt(args[++argnum]);
        } else if (args[argnum].equals("--arraysize")) {
          size = Integer.parseInt(args[++argnum]);
        } else {
          throw new Exception("Unknown cmdline parameter '"
                              + args[argnum] + "'.");
        }
      }
    } catch (Exception e) {
      System.err.println("Error parsing command line: " + e + NL);
      System.err.println(usage);
      System.exit(1);
    }

    // Initial the array with random integers
    int[] array = new int[size];
    Random random = new Random();
    for (int i = 0 ; i < size ; ++i) {
      array[i] = random.nextInt();
    }
    
    int k = 0;
    if (useIndexedLoop) {
      System.out.println("Indexed : " + iterations + " iterations : "
                         + size + " elements");
      for (int m = 0 ; m < iterations ; ++m) {
        for (int j = 0 ; j < size ; ++j) {
          k = array[j];
        }
      }
    } else { // useIndexedLoop = false
      System.out.println("For-each : " + iterations + " iterations : "
                         + size + " elements");
      for (int m = 0 ; m < iterations ; ++m) {
        for (int j : array) {
          k = j;
        }
      }
    }
    k = 0;
  }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: java-dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: java-dev-help@lucene.apache.org


Mime
View raw message