content: //   PerformanceTest.java
  //   Java Spatial Index Library
  //   Copyright (C) 2002-2005 Infomatiq Limited.
  //   Copyright (C) 2013 Aled Morris <aled@users.sourceforge.net>
  //
  //  
  //  This library is free software; you can redistribute it and/or
  //  modify it under the terms of the GNU Lesser General Public
  //  License as published by the Free Software Foundation; either
  //  version 2.1 of the License, or (at your option) any later version.
  //  
  //  This library is distributed in the hope that it will be useful,
  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  //  Lesser General Public License for more details.
  //  
  //  You should have received a copy of the GNU Lesser General Public
  //  License along with this library; if not, write to the Free Software
  //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  
  package net.sf.jsi;
  
  import java.util.Properties;
  import java.util.Random;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  import java.util.concurrent.TimeUnit;
  
  import net.sf.jsi.rtree.RTree;
  import gnu.trove.procedure.TIntProcedure;
  
  import org.junit.Test;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * PerformanceTest
   *  
   * Generates results used for comparing the performance of the Java Spatial 
   * Index library against alternative implementations.
   *
   * The idea is for the raw data to be imported into a database, and results
   * extracted from that.
   *
   * This test requires 1024M memory (i.e. use -Xmx1024M)
   */
  public class PerformanceTest {
  
    private static final Logger log = LoggerFactory.getLogger(PerformanceTest.class);
    private SpatialIndex si;
  
    private float randomFloat(Random r, float min, float max) {
      return (r.nextFloat() * (max - min)) + min;
    }
  
    protected Point randomPoint(Random r) {
      return new Point(randomFloat(r, 0, 100), randomFloat(r, 0, 100));
    }
  
    private Rectangle randomRectangle(Random r, float size) {
      float x = randomFloat(r, 0, 100);
      float y = randomFloat(r, 0, 100);
      return new Rectangle(x, y, x + randomFloat(r, 0, size), y + randomFloat(r, 0, size));
    }
  
    abstract class Operation {
      private final int count[] = new int[1];
      private String description;
      public Random r;
  
      public Operation(String description, Random r) {
        this.description = description;
        this.r = r;
      }
  
      protected TIntProcedure countProc = new TIntProcedure() {
        public boolean execute(int value) {
          count[0]++;
          return true;
        }
      };
  
      public int callbackCount() {
        return count[0];
      }
  
      public String getDescription() {
        return description;
      }
  
      abstract void execute(SpatialIndex si, Random r);
    }
  
    private void benchmark(Operation o, int repetitions) {
      long duration = 0;
      long startTime = System.nanoTime();
      for (int j = 0; j < repetitions; j++) o.execute(si, o.r);
      duration += (System.nanoTime() - startTime);
  
      log.info(o.getDescription() + ", " +
              "avg callbacks = " + ((float) o.callbackCount() / repetitions) + ", " +
              "avg time = " + (duration / repetitions) + " ns");
    }
  
    /**
     * First attempt at a benchmark
     */
    @Test
    public void benchmark_1() {
      Random rand  = new Random(0);
      Properties p = new Properties();
      p.setProperty("MinNodeEntries", "20");
      p.setProperty("MaxNodeEntries", "50");
      si = new RTree();
      si.init(p);
  
      final int rectangleCount = 1000000;
      final Rectangle[] rects = new Rectangle[rectangleCount];
      for (int i = 0; i < rectangleCount; i++) {
        rects[i] = randomRectangle(rand, 0.01f);
      }
  
      long duration;
      long startTime;
  
      for (int j = 0; j < 5; j++) {
        duration = 0;
        startTime = System.nanoTime();
        for (int i = 0; i < rectangleCount; i++) {
          si.add(rects[i], i);
        }
        duration += (System.nanoTime() - startTime);
        log.info("add " + rectangleCount + " avg tme = " + (duration / rectangleCount) + " ns");
  
        if (j == 4) break; // don't do the delete on the last iteration
  
        duration = 0;
        startTime = System.nanoTime();
        for (int i = 0; i < rectangleCount; i++) {
          si.delete(rects[i], i);
        }
        duration += (System.nanoTime() - startTime);
        log.info("delete " + rectangleCount + " avg tme = " + (duration / rectangleCount) + " ns");
      }
  
      ExecutorService exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
      try {
        for (int i = 0; i < 100; i++) {
          exec.submit(new Runnable() {public void run() {benchmark(new Operation("nearest", new Random(0)) {void execute(SpatialIndex si, Random r) {si.nearest(randomPoint(r), countProc, 0.1f);}}, 100); }});
          exec.submit(new Runnable() {public void run() {benchmark(new Operation("nearestNUnsorted", new Random(0)) {void execute(SpatialIndex si, Random r) {si.nearestNUnsorted(randomPoint(r), countProc, 10, 0.16f);}}, 100); }});
          exec.submit(new Runnable() {public void run() {benchmark(new Operation("nearestN", new Random(0)) {void execute(SpatialIndex si, Random r) {si.nearestN(randomPoint(r), countProc, 10, 0.16f);}}, 100); }});
          exec.submit(new Runnable() {public void run() {benchmark(new Operation("intersects", new Random(0)) {void execute(SpatialIndex si, Random r) {si.intersects(randomRectangle(r, 0.6f), countProc);}}, 100); }});
          exec.submit(new Runnable() {public void run() {benchmark(new Operation("contains", new Random(0)) {void execute(SpatialIndex si, Random r) {si.contains(randomRectangle(r, 0.65f), countProc);}}, 100); }});
        }
        try { exec.awaitTermination(1, TimeUnit.DAYS); } catch (Exception e) {}
      }
      finally {
        exec.shutdown();
      }
    }
  }
  