Skip to content

Commit

Permalink
add real benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
msbarry committed Nov 5, 2024
1 parent 31729d0 commit 3a7ea0f
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,86 +2,111 @@

import com.onthegomap.planetiler.geo.GeoUtils;
import com.onthegomap.planetiler.util.Format;
import com.onthegomap.planetiler.util.Gzip;
import com.onthegomap.planetiler.util.LoopLineMerger;
import com.onthegomap.planetiler.util.Try;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.CoordinateXY;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.operation.linemerge.LineMerger;

public class BenchmarkLineMerge {
private static int numLines;

public static void main(String[] args) {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
System.err.println(
" JTS line merger (/s):\t" +
timeJts(10, 10) + "\t" +
timeJts(10, 100) + "\t" +
timeJts(1000, 10) + "\t" +
timeJts(1000, 1000));
System.err.println(
"loop line merger (/s):\t" +
timeLoop(10, 10) + "\t" +
timeLoop(10, 100) + "\t" +
timeLoop(1000, 10));
// TODO currently this does not finish:
// + "\t" + timeLoop(1000, 1000));
System.err.println();
time(" JTS", geom -> {
var lm = new LineMerger();
lm.add(geom);
return lm.getMergedLineStrings();
});
time(" loop(0)", geom -> {
var lm = new LoopLineMerger();
lm.setLoopMinLength(0);
lm.setMinLength(0);
lm.add(geom);
return lm.getMergedLineStrings();
});
time("loop(0.1)", geom -> {
var lm = new LoopLineMerger();
lm.setLoopMinLength(0.1);
lm.setMinLength(0.1);
lm.add(geom);
return lm.getMergedLineStrings();
});
System.out.println(numLines);
numLines = 0;
}
}

private static String timeLoop(int lines, int parts) {
return time(lines, parts, geom -> {
var merger = new LoopLineMerger();
merger.add(geom);
merger.setLoopMinLength(0.1);
merger.setMinLength(0.1);
return merger.getMergedLineStrings();
});
private static void time(String name, Function<Geometry, Collection<LineString>> fn) throws Exception {
System.err.println(String.join("\t",
name,
timeMillis(() -> fn.apply(read("mergelines_200433_lines.wkb.gz"))),
timeMillis(() -> fn.apply(read("mergelines_239823_lines.wkb.gz"))),
"(/s):",
timePerSec(() -> fn.apply(read("mergelines_1759_point_line.wkb.gz"))),
timePerSec(() -> fn.apply(makeLines(50, 2))),
timePerSec(() -> fn.apply(makeLines(10, 10))),
timePerSec(() -> fn.apply(makeLines(2, 50)))
));
}

private static String timeJts(int lines, int parts) {
return time(lines, parts, geom -> {
var merger = new LineMerger();
merger.add(geom);
return merger.getMergedLineStrings();
});
}

private static String time(int lines, int parts, Function<Geometry, Collection<LineString>> fn) {
Geometry multiLinestring = makeLines(lines, parts);
private static String timePerSec(Try.SupplierThatThrows<Collection<LineString>> fn) throws Exception {
long start = System.nanoTime();
long end = start + Duration.ofSeconds(1).toNanos();
int num = 0;
for (; System.nanoTime() < end;) {
fn.apply(multiLinestring);
numLines += fn.get().size();
num++;
}
return Format.defaultInstance()
.numeric(Math.round(num * 1d / ((System.nanoTime() - start) * 1d / Duration.ofSeconds(1).toNanos())), true);
}

private static String timeMillis(Try.SupplierThatThrows<Collection<LineString>> fn) throws Exception {
long start = System.nanoTime();
long end = start + Duration.ofSeconds(1).toNanos();
int num = 0;
for (; System.nanoTime() < end;) {
numLines += fn.get().size();
num++;
}
// equivalent of toPrecision(3)
long nanosPer = (System.nanoTime() - start) / num;
var bd = new BigDecimal(nanosPer, new MathContext(3));
return Format.padRight(Duration.ofNanos(bd.longValue()).toString().replace("PT", ""), 6);
}


private static Geometry read(String fileName) throws IOException, ParseException {
var path = Path.of("planetiler-core", "src", "test", "resources", "mergelines", fileName);
byte[] bytes = Gzip.gunzip(Files.readAllBytes(path));
return new WKBReader().read(bytes);
}

private static Geometry makeLines(int lines, int parts) {
List<LineString> result = new ArrayList<>();
var random = new Random();
double idx = 0;
for (int i = 0; i < lines; i++) {
Coordinate[] coords = new Coordinate[parts];
double startX = random.nextInt(100);
double startY = random.nextInt(100);
double endX = random.nextInt(100);
double endY = random.nextInt(100);
for (int j = 0; j < parts; j++) {
coords[j] = new CoordinateXY(
j * (endX - startX) / parts + startX,
j * (endY - startY) / parts + startY
);
coords[j] = new CoordinateXY(idx, idx);
idx += 0.5;
}
result.add(GeoUtils.JTS_FACTORY.createLineString(coords));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
package com.onthegomap.planetiler.util;

import static com.onthegomap.planetiler.TestUtils.newLineString;
import static com.onthegomap.planetiler.TestUtils.newPoint;
import static org.junit.jupiter.api.Assertions.assertEquals;

import com.onthegomap.planetiler.TestUtils;
import com.onthegomap.planetiler.geo.GeoUtils;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;

class LoopLineMergerTest {

Expand Down Expand Up @@ -162,11 +172,7 @@ void testMerge() {
.setLoopMinLength(100);

/**
* 10 20 30 40
* 10 o--o--o
* \ |
* \|
* 20 o--o
* 10 20 30 40 10 o--o--o \ | \| 20 o--o
*/
merger.add(newLineString(
10, 10,
Expand Down Expand Up @@ -197,11 +203,7 @@ void testMerge() {
.setLoopMinLength(0.001);

/**
* 10 20 30 40
* 10 o--o--o
* \ |
* \|
* 20 o--o
* 10 20 30 40 10 o--o--o \ | \| 20 o--o
*/
merger.add(newLineString(
10, 10,
Expand Down Expand Up @@ -250,18 +252,15 @@ void testMerge() {
merger.getMergedLineStrings()
);

// removes first short stubs, merges again, and only then
// removes first short stubs, merges again, and only then
// removes non-stubs that are too short
// stub = linestring that has at least one disconnected end
merger = new LoopLineMerger()
.setMinLength(15)
.setLoopMinLength(-1);

/**
* 0 20 30 50
* 0 o----o--o----o
* | |
* 10 o o
* 0 20 30 50 0 o----o--o----o | | 10 o o
*/
merger.add(newLineString(0, 0, 20, 0));
merger.add(newLineString(20, 0, 30, 0));
Expand Down Expand Up @@ -308,11 +307,8 @@ void testHasPointAppearingMoreThanTwice() {
void testFindAllPaths() {
// finds all paths and orders them by length
var merger = new LoopLineMerger();
/** 10 20 30
* 10 o-----o
* |\ |
* | \ |
* 20 o--o--o
/**
* 10 20 30 10 o-----o |\ | | \ | 20 o--o--o
*/
merger.add(newLineString(10, 10, 30, 10));
merger.add(newLineString(10, 10, 10, 20));
Expand Down Expand Up @@ -344,5 +340,32 @@ void testFindAllPaths() {
allPaths.get(2)
);
}



@ParameterizedTest
@CsvSource({
"mergelines_1759_point_line.wkb.gz,0,4",
"mergelines_1759_point_line.wkb.gz,1,2",

"mergelines_200433_lines.wkb.gz,0,35160",
"mergelines_200433_lines.wkb.gz,0.1,22403",
"mergelines_200433_lines.wkb.gz,1,1516",

"mergelines_239823_lines.wkb.gz,0,19632",
"mergelines_239823_lines.wkb.gz,0.1,13861",
"mergelines_239823_lines.wkb.gz,1,1585",
})
void testOnRealWorldData(String file, double minLengths, int expected)
throws IOException, ParseException {
// finds all paths and orders them by length
Geometry geom = new WKBReader(GeoUtils.JTS_FACTORY).read(
Gzip.gunzip(Files.readAllBytes(TestUtils.pathToResource("mergelines").resolve(file))));
var merger = new LoopLineMerger();
merger.setMinLength(minLengths);
merger.setLoopMinLength(minLengths);
merger.add(geom);
merger.getMergedLineStrings();
assertEquals(expected, merger.getMergedLineStrings().size());
}

}
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit 3a7ea0f

Please sign in to comment.