Skip to content

Commit

Permalink
Add benchmarks for Flatbush and JTS STR RTree
Browse files Browse the repository at this point in the history
The flatbush provides performance benefits over the JTS tree, with over
4x query speed at 1M build geometries, and 2.5x faster builds.

Benchmarks (included in change)
Query Benchmark                     (numBuildRects)  Mode  Cnt    Score    Error  Units
JTS STR RTree
BenchmarkJtsStrTreeQuery.rtreeQuery            1000  avgt   20    0.439 ±  0.006  us/op
BenchmarkJtsStrTreeQuery.rtreeQuery            3000  avgt   20    0.778 ±  0.010  us/op
BenchmarkJtsStrTreeQuery.rtreeQuery           10000  avgt   20    1.675 ±  0.017  us/op
BenchmarkJtsStrTreeQuery.rtreeQuery           30000  avgt   20    4.208 ±  0.565  us/op
BenchmarkJtsStrTreeQuery.rtreeQuery          100000  avgt   20   18.533 ±  0.786  us/op
BenchmarkJtsStrTreeQuery.rtreeQuery          300000  avgt   20   59.184 ±  1.175  us/op
BenchmarkJtsStrTreeQuery.rtreeQuery         1000000  avgt   20  250.904 ± 10.420  us/op

Flatbush (degree 16)
BenchmarkFlatbushQuery.rtreeQuery              1000  avgt   20    0.578 ±  0.019  us/op
BenchmarkFlatbushQuery.rtreeQuery              3000  avgt   20    0.902 ±  0.013  us/op
BenchmarkFlatbushQuery.rtreeQuery             10000  avgt   20    1.667 ±  0.018  us/op
BenchmarkFlatbushQuery.rtreeQuery             30000  avgt   20    3.329 ±  0.033  us/op
BenchmarkFlatbushQuery.rtreeQuery            100000  avgt   20    9.435 ±  0.599  us/op
BenchmarkFlatbushQuery.rtreeQuery            300000  avgt   20   27.564 ±  0.851  us/op
BenchmarkFlatbushQuery.rtreeQuery           1000000  avgt   20   72.725 ±  0.582  us/op

Build Benchmark                     (numBuildRects)  Mode  Cnt     Score    Error  Units
JTS STR RTree
BenchmarkJtsStrTreeBuild.buildRtree            1000  avgt   20     0.306 ±  0.020  ms/op
BenchmarkJtsStrTreeBuild.buildRtree            3000  avgt   20     1.077 ±  0.023  ms/op
BenchmarkJtsStrTreeBuild.buildRtree           10000  avgt   20     4.542 ±  0.055  ms/op
BenchmarkJtsStrTreeBuild.buildRtree           30000  avgt   20    15.837 ±  0.414  ms/op
BenchmarkJtsStrTreeBuild.buildRtree          100000  avgt   20    77.911 ±  2.883  ms/op
BenchmarkJtsStrTreeBuild.buildRtree          300000  avgt   20   309.898 ±  7.493  ms/op
BenchmarkJtsStrTreeBuild.buildRtree         1000000  avgt   20  1325.381 ± 67.566  ms/op

Flatbush (degree 16)
BenchmarkFlatbushBuild.buildRtree              1000  avgt   20     0.503 ±  0.007  ms/op
BenchmarkFlatbushBuild.buildRtree              3000  avgt   20     1.786 ±  0.017  ms/op
BenchmarkFlatbushBuild.buildRtree             10000  avgt   20     3.213 ±  0.154  ms/op
BenchmarkFlatbushBuild.buildRtree             30000  avgt   20     9.667 ±  0.389  ms/op
BenchmarkFlatbushBuild.buildRtree            100000  avgt   20    30.333 ±  0.559  ms/op
BenchmarkFlatbushBuild.buildRtree            300000  avgt   20    98.058 ±  2.014  ms/op
BenchmarkFlatbushBuild.buildRtree           1000000  avgt   20   367.947 ±  5.481  ms/op
  • Loading branch information
jagill authored and mbasmanova committed Aug 22, 2019
1 parent 9124aa4 commit 394c8c3
Show file tree
Hide file tree
Showing 4 changed files with 413 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.presto.geospatial.rtree;

import com.facebook.presto.geospatial.Rectangle;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OperationsPerInvocation;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.VerboseMode;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import static com.facebook.presto.geospatial.rtree.RtreeTestUtils.makeRectangles;

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(2)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)
@BenchmarkMode(Mode.AverageTime)
public class BenchmarkFlatbushBuild
{
private static final int SEED = 613;

@Benchmark
@OperationsPerInvocation(1)
public void buildRtree(BenchmarkData data, Blackhole blackhole)
{
blackhole.consume(new Flatbush<>(
data.getBuildRectangles().toArray(new Rectangle[] {}),
data.getRtreeDegree()));
}

@State(Scope.Thread)
public static class BenchmarkData
{
@Param({"8", "16", "32"})
private int rtreeDegree;
@Param({"1000", "3000", "10000", "30000", "100000", "300000", "1000000"})
private int numBuildRectangles;

private List<Rectangle> buildRectangles;

@Setup
public void setup()
{
Random random = new Random(SEED);
buildRectangles = makeRectangles(random, numBuildRectangles);
}

public int getRtreeDegree()
{
return rtreeDegree;
}

public List<Rectangle> getBuildRectangles()
{
return buildRectangles;
}
}

public static void main(String[] args)
throws Throwable
{
Options options = new OptionsBuilder()
.verbosity(VerboseMode.NORMAL)
.include(".*" + BenchmarkFlatbushBuild.class.getSimpleName() + ".*")
.build();
new Runner(options).run();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.presto.geospatial.rtree;

import com.facebook.presto.geospatial.Rectangle;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OperationsPerInvocation;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.VerboseMode;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import static com.facebook.presto.geospatial.rtree.RtreeTestUtils.makeRectangles;

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(2)
@Warmup(iterations = 3, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
@BenchmarkMode(Mode.AverageTime)
public class BenchmarkFlatbushQuery
{
private static final int SEED = 613;
private static final int NUM_PROBE_RECTANGLES = 1000;

@Benchmark
@OperationsPerInvocation(NUM_PROBE_RECTANGLES)
public void rtreeQuery(BenchmarkData data, Blackhole blackhole)
{
for (Rectangle query : data.getProbeRectangles()) {
data.getRtree().findIntersections(query, blackhole::consume);
}
}

@State(Scope.Thread)
public static class BenchmarkData
{
@Param({"8", "16", "32"})
private int rtreeDegree;
@Param({"1000", "3000", "10000", "30000", "100000", "300000", "1000000"})
private int numBuildRectangles;

private List<Rectangle> probeRectangles;
private Flatbush<Rectangle> rtree;

@Setup
public void setup()
{
Random random = new Random(SEED);
probeRectangles = makeRectangles(random, NUM_PROBE_RECTANGLES);
rtree = buildRtree(makeRectangles(random, numBuildRectangles));
}

public List<Rectangle> getProbeRectangles()
{
return probeRectangles;
}

public Flatbush<Rectangle> getRtree()
{
return rtree;
}

private Flatbush<Rectangle> buildRtree(List<Rectangle> rectangles)
{
return new Flatbush<>(rectangles.toArray(new Rectangle[] {}), rtreeDegree);
}
}

public static void main(String[] args)
throws Throwable
{
Options options = new OptionsBuilder()
.verbosity(VerboseMode.NORMAL)
.include(".*" + BenchmarkFlatbushQuery.class.getSimpleName() + ".*")
.build();
new Runner(options).run();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.presto.geospatial.rtree;

import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.index.strtree.STRtree;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OperationsPerInvocation;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.VerboseMode;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.facebook.presto.geospatial.rtree.RtreeTestUtils.makeRectangles;

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(2)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)
@BenchmarkMode(Mode.AverageTime)
public class BenchmarkJtsStrTreeBuild
{
private static final int SEED = 613;

@Benchmark
@OperationsPerInvocation(1)
public void buildRtree(BenchmarkData data, Blackhole blackhole)
{
STRtree rtree = new STRtree();
for (Envelope envelope : data.getBuildEnvelopes()) {
rtree.insert(envelope, envelope);
}
rtree.build();
blackhole.consume(rtree);
}

@State(Scope.Thread)
public static class BenchmarkData
{
@Param({"1000", "3000", "10000", "30000", "100000", "300000", "1000000"})
private int numBuildEnvelopes;

private List<Envelope> buildEnvelopes;

@Setup
public void setup()
{
buildEnvelopes = makeRectangles(new Random(SEED), numBuildEnvelopes).stream()
.map(rectangle -> new Envelope(rectangle.getXMin(), rectangle.getXMax(), rectangle.getYMin(), rectangle.getYMax()))
.collect(Collectors.toList());
}

public List<Envelope> getBuildEnvelopes()
{
return buildEnvelopes;
}
}

public static void main(String[] args)
throws Throwable
{
Options options = new OptionsBuilder()
.verbosity(VerboseMode.NORMAL)
.include(".*" + BenchmarkJtsStrTreeBuild.class.getSimpleName() + ".*")
.build();
new Runner(options).run();
}
}
Loading

0 comments on commit 394c8c3

Please sign in to comment.