performance patches

This commit is contained in:
Arndt 2014-12-28 08:03:27 +01:00
parent 176beba6f6
commit 46db0104e5
13 changed files with 469 additions and 280 deletions

View file

@ -1,172 +0,0 @@
/**
* Implementation for the open-set
* that should be somewhat faster
* and memory-efficient than the original
* version based on java.util.TreeSet
*
* It relies on the two double-linked
* lists implemented in OsmPath
*
* @author ab
*/
package btools.router;
import btools.mapaccess.OsmNode;
public class OpenSet
{
private OsmPath start = new OsmPath();
private OsmPath index2 = new OsmPath();
private int addCount = 0;
private int size = 0;
public void clear()
{
start.nextInSet = null;
start.nextInIndexSet = null;
index2.nextInIndexSet = null;
size = 0;
addCount = 0;
}
public void add( OsmPath path )
{
int ac = path.adjustedCost;
OsmPath p1 = index2;
// fast forward along index2
while( p1.nextInIndexSet != null && p1.nextInIndexSet.adjustedCost < ac )
{
p1 = p1.nextInIndexSet;
}
if ( p1 == index2 )
{
p1 = start;
}
// search using index1
for(;;)
{
if ( p1.nextInIndexSet != null && p1.nextInIndexSet.adjustedCost < ac )
{
p1 = p1.nextInIndexSet;
}
else if ( p1.nextInSet != null && p1.nextInSet.adjustedCost < ac )
{
p1 = p1.nextInSet;
}
else
{
break;
}
}
OsmPath p2 = p1.nextInSet;
p1.nextInSet = path;
path.prevInSet = p1;
path.nextInSet = p2;
if ( p2 != null ) { p2.prevInSet = path; }
size++;
addCount++;
// feed random samples to the indices
if ( (addCount & 31) == 0 )
{
addIndex( path, start );
}
else if ( (addCount & 1023) == 1023 )
{
addIndex( path, index2 );
}
}
public void remove( OsmPath path )
{
OsmPath p1 = path.prevInSet;
OsmPath p2 = path.nextInSet;
if ( p1 == null )
{
return; // not in set
}
path.prevInSet = null;
path.nextInSet = null;
if ( p2 != null )
{
p2.prevInSet = p1;
}
p1.nextInSet = p2;
removeIndex( path );
size--;
}
public OsmPath first()
{
return start.nextInSet;
}
public int size()
{
return size;
}
public int[] getExtract()
{
int div = size / 1000 + 1;
int[] res = new int[size/div * 2];
int i = 0;
int cnt = 0;
for( OsmPath p = start.nextInSet; p != null; p = p.nextInSet )
{
if ( (++cnt) % div == 0 )
{
OsmNode n = p.getLink().targetNode;
res[i++] = n.ilon;
res[i++] = n.ilat;
}
}
return res;
}
// index operations
private void addIndex( OsmPath path, OsmPath index )
{
int ac = path.adjustedCost;
OsmPath p1 = index;
OsmPath p2 = p1.nextInIndexSet;
while( p2 != null && p2.adjustedCost < ac )
{
p1 = p2;
p2 = p2.nextInIndexSet;
}
p1.nextInIndexSet = path;
path.prevInIndexSet = p1;
path.nextInIndexSet = p2;
if ( p2 != null ) { p2.prevInIndexSet = path; }
}
private void removeIndex( OsmPath path )
{
OsmPath p1 = path.prevInIndexSet;
OsmPath p2 = path.nextInIndexSet;
if ( p1 == null )
{
return; // not in set
}
path.prevInIndexSet = null;
path.nextInIndexSet = null;
if ( p2 != null )
{
p2.prevInIndexSet = p1;
}
p1.nextInIndexSet = p2;
}
}

View file

@ -9,12 +9,6 @@ import btools.mapaccess.*;
final class OsmPath implements OsmLinkHolder
{
// double-linked lists for the openSet
public OsmPath nextInSet;
public OsmPath prevInSet;
public OsmPath nextInIndexSet;
public OsmPath prevInIndexSet;
/**
* The cost of that path (a modified distance)
*/
@ -30,12 +24,7 @@ final class OsmPath implements OsmLinkHolder
// if the corresponding node has not
public short selev;
public int adjustedCost = 0;
public void setAirDistanceCostAdjustment( int costAdjustment )
{
adjustedCost = cost + costAdjustment;
}
public int airdistance = 0; // distance to endpos
private OsmNode sourcenode;
private OsmLink link;

View file

@ -18,6 +18,7 @@ import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import btools.mapaccess.OsmPos;
import btools.util.CompactLongMap;
@ -219,7 +220,7 @@ public final class OsmTrack
sb.append( " xmlns=\"http://www.topografix.com/GPX/1/1\" \n" );
sb.append( " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" );
sb.append( " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" \n" );
sb.append( " creator=\"BRouter-1.0.4\" version=\"1.1\">\n" );
sb.append( " creator=\"BRouter-1.1\" version=\"1.1\">\n" );
sb.append( " <trk>\n" );
sb.append(" <name>").append(name).append("</name>\n");
sb.append( " <trkseg>\n" );
@ -286,6 +287,8 @@ public final class OsmTrack
return sb.toString();
}
public List<String> iternity;
public String formatAsGeoJson()
{
StringBuilder sb = new StringBuilder(8192);
@ -296,13 +299,24 @@ public final class OsmTrack
sb.append( " {\n" );
sb.append( " \"type\": \"Feature\",\n" );
sb.append( " \"properties\": {\n" );
sb.append( " \"creator\": \"BRouter-1.0.4\",\n" );
sb.append( " \"creator\": \"BRouter-1.1\",\n" );
sb.append( " \"name\": \"" ).append( name ).append( "\",\n" );
sb.append( " \"track-length\": \"" ).append( distance ).append( "\",\n" );
sb.append( " \"filtered ascend\": \"" ).append( ascend ).append( "\",\n" );
sb.append( " \"plain-ascend\": \"" ).append( plainAscend ).append( "\",\n" );
sb.append( " \"cost\": \"" ).append( cost ).append( "\"\n" );
sb.append( " },\n" );
if ( iternity != null )
{
sb.append( " \"iternity\": [\n" );
for( String s : iternity )
{
sb.append( " \"").append( s ).append( "\",\n" );
}
sb.deleteCharAt( sb.lastIndexOf( "," ) );
sb.append( " ],\n" );
}
sb.append( " \"geometry\": {\n" );
sb.append( " \"type\": \"LineString\",\n" );
sb.append( " \"coordinates\": [\n" );

View file

@ -40,6 +40,8 @@ public final class RoutingContext implements DistanceChecker
public BExpressionContext expctxWay;
public BExpressionContext expctxNode;
public boolean serversizing = false;
public int downhillcostdiv;
public int downhillcutoff;
public int uphillcostdiv;
@ -51,6 +53,12 @@ public final class RoutingContext implements DistanceChecker
public int elevationpenaltybuffer;
public int elevationmaxbuffer;
public int elevationbufferreduce;
public double cost1speed;
public double additionalcostfactor;
public double changetime;
public double buffertime;
public double waittimeadjustment;
public void readGlobalConfig( BExpressionContext expctxGlobal )
{
@ -67,6 +75,12 @@ public final class RoutingContext implements DistanceChecker
elevationpenaltybuffer = (int)(expctxGlobal.getVariableValue( "elevationpenaltybuffer", 5.f )*1000000);
elevationmaxbuffer = (int)(expctxGlobal.getVariableValue( "elevationmaxbuffer", 10.f )*1000000);
elevationbufferreduce = (int)(expctxGlobal.getVariableValue( "elevationbufferreduce", 0.f )*10000);
cost1speed = expctxGlobal.getVariableValue( "cost1speed", 22.f );
additionalcostfactor = expctxGlobal.getVariableValue( "additionalcostfactor", 1.5f );
changetime = expctxGlobal.getVariableValue( "changetime", 180.f );
buffertime = expctxGlobal.getVariableValue( "buffertime", 120.f );
waittimeadjustment = expctxGlobal.getVariableValue( "waittimeadjustment", 0.9f );
}
public RoutingMessageHandler messageHandler = new RoutingMessageHandler();

View file

@ -15,32 +15,33 @@ import btools.mapaccess.OsmLink;
import btools.mapaccess.OsmLinkHolder;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmNodesMap;
import btools.util.SortedHeap;
public class RoutingEngine extends Thread
{
private OsmNodesMap nodesMap;
private NodesCache nodesCache;
private OpenSet openSet = new OpenSet();
private SortedHeap<OsmPath> openSet = new SortedHeap<OsmPath>();
private boolean finished = false;
private List<OsmNodeNamed> waypoints = null;
protected List<OsmNodeNamed> waypoints = null;
private int linksProcessed = 0;
private OsmTrack foundTrack = new OsmTrack();
protected OsmTrack foundTrack = new OsmTrack();
private OsmTrack foundRawTrack = null;
private int alternativeIndex = 0;
private String errorMessage = null;
protected String errorMessage = null;
private volatile boolean terminated;
private File profileDir;
private String segmentDir;
protected File profileDir;
protected String segmentDir;
private String outfileBase;
private String logfileBase;
private boolean infoLogEnabled;
private Writer infoLogWriter;
private RoutingContext routingContext;
protected RoutingContext routingContext;
private double airDistanceCostFactor;
private OsmTrack guideTrack;
@ -80,8 +81,8 @@ public class RoutingEngine extends Thread
BExpressionMetaData meta = new BExpressionMetaData();
BExpressionContext expctxGlobal = new BExpressionContext( "global", meta );
rc.expctxWay = new BExpressionContext( "way", meta );
rc.expctxNode = new BExpressionContext( "node", 1024, meta );
rc.expctxWay = new BExpressionContext( "way", rc.serversizing ? 262144 : 4096, meta );
rc.expctxNode = new BExpressionContext( "node", rc.serversizing ? 16384 : 1024, meta );
meta.readMetaData( new File( profileDir, "lookups.dat" ) );
@ -504,7 +505,6 @@ public class RoutingEngine extends Thread
if ( pe.cost >= costdelta )
{
pe.cost -= costdelta;
pe.adjustedCost -= costdelta;
if ( guideTrack != null )
{
@ -559,7 +559,7 @@ public class RoutingEngine extends Thread
wp.radius = 1e9;
OsmPath testPath = new OsmPath( null, startPath, link, null, guideTrack != null, routingContext );
testPath.setAirDistanceCostAdjustment( (int)( nextNode.calcDistance( endPos ) * airDistanceCostFactor ) );
testPath.airdistance = nextNode.calcDistance( endPos );
if ( wp.radius < minradius )
{
bestPath = testPath;
@ -593,10 +593,7 @@ public class RoutingEngine extends Thread
if ( wp != null ) wp.radius = 1e-5;
OsmPath testPath = new OsmPath( n1, startPath, link, null, guideTrack != null, routingContext );
testPath.setAirDistanceCostAdjustment( 0 );
return testPath;
return new OsmPath( n1, startPath, link, null, guideTrack != null, routingContext );
}
finally
{
@ -636,8 +633,6 @@ public class RoutingEngine extends Thread
OsmPath startPath1 = getStartPath( start1, start2, startWp, endWp, sameSegmentSearch );
OsmPath startPath2 = getStartPath( start2, start1, startWp, endWp, sameSegmentSearch );
int maxAdjCostFromQueue = 0;
// check for an INITIAL match with the cost-cutting-track
if ( costCuttingTrack != null )
{
@ -655,8 +650,8 @@ public class RoutingEngine extends Thread
synchronized( openSet )
{
openSet.clear();
if ( startPath1.cost >= 0 ) openSet.add( startPath1 );
if ( startPath2.cost >= 0 ) openSet.add( startPath2 );
addToOpenset( startPath1 );
addToOpenset( startPath2 );
}
while(!terminated)
{
@ -671,16 +666,10 @@ public class RoutingEngine extends Thread
OsmPath path = null;
synchronized( openSet )
{
if ( openSet.size() == 0 ) break;
path = openSet.first();
openSet.remove( path );
path = openSet.popLowestKeyValue();
}
if ( path.adjustedCost < maxAdjCostFromQueue && airDistanceCostFactor == 0.)
{
throw new RuntimeException( "assertion failed: path.adjustedCost < maxAdjCostFromQueue: " + path.adjustedCost + "<" + maxAdjCostFromQueue );
}
maxAdjCostFromQueue = path.adjustedCost;
if ( path == null ) break;
if ( path.airdistance == -1 ) continue;
if ( matchPath != null && fastPartialRecalc && firstMatchCost < 500 && path.cost > 30L*firstMatchCost )
{
@ -740,8 +729,7 @@ public class RoutingEngine extends Thread
}
// recheck cutoff before doing expensive stuff
int airDistance2 = currentNode.calcDistance( endPos );
if ( path.cost + airDistance2 > maxTotalCost + 10 )
if ( path.cost + path.airdistance > maxTotalCost + 10 )
{
continue;
}
@ -824,18 +812,14 @@ public class RoutingEngine extends Thread
}
if ( otherPath != path )
{
synchronized( openSet )
{
openSet.remove( otherPath );
}
otherPath.airdistance = -1; // invalidate the entry in the open set
}
}
if ( bestPath != null )
{
int airDistance = isFinalLink ? 0 : nextNode.calcDistance( endPos );
bestPath.setAirDistanceCostAdjustment( (int)( airDistance * airDistanceCostFactor ) );
bestPath.airdistance = isFinalLink ? 0 : nextNode.calcDistance( endPos );
if ( isFinalLink || bestPath.cost + airDistance <= maxTotalCost + 10 )
if ( isFinalLink || bestPath.cost + bestPath.airdistance <= maxTotalCost + 10 )
{
// add only if this may beat an existing path for that link
OsmLinkHolder dominator = link.firstlinkholder;
@ -854,7 +838,7 @@ public class RoutingEngine extends Thread
link.addLinkHolder( bestPath );
synchronized( openSet )
{
openSet.add( bestPath );
addToOpenset( bestPath );
}
}
}
@ -869,6 +853,14 @@ public class RoutingEngine extends Thread
}
return null;
}
private void addToOpenset( OsmPath path )
{
if ( path.cost >= 0 )
{
openSet.add( path.cost + (int)(path.airdistance*airDistanceCostFactor), path );
}
}
private void preloadPosition( OsmNode n, int minRingWidth, int minCount )
{
@ -991,7 +983,16 @@ public class RoutingEngine extends Thread
{
synchronized( openSet )
{
return openSet.getExtract();
List<OsmPath> extract = openSet.getExtract();
int[] res = new int[extract.size() * 2];
int i = 0;
for( OsmPath p : extract )
{
OsmNode n = p.getLink().targetNode;
res[i++] = n.ilon;
res[i++] = n.ilat;
}
return res;
}
}
@ -1044,4 +1045,10 @@ public class RoutingEngine extends Thread
{
terminated = true;
}
public boolean isTerminated()
{
return terminated;
}
}