From f70dd3c3aced590ade6924496cf0f15ec6bf7d3c Mon Sep 17 00:00:00 2001 From: Arndt Date: Sat, 20 Aug 2016 18:53:50 +0200 Subject: [PATCH] removed some old stuff, added profiler, minor performance tuning --- .../main/java/btools/codec/MicroCache1.java | 99 --------- .../src/main/java/btools/router/OsmPath.java | 45 ++-- .../java/btools/router/RoutingContext.java | 7 +- .../java/btools/router/RoutingEngine.java | 118 ++-------- .../btools/router/RoutingMessageHandler.java | 28 --- .../java/btools/expressions/BExpression.java | 7 - .../expressions/BExpressionContext.java | 35 ++- .../expressions/BExpressionContextWay.java | 4 +- .../expressions/BExpressionReceiver.java | 7 - .../btools/expressions/EncodeDecodeTest.java | 2 +- .../java/btools/mapcreator/OsmCutter.java | 4 +- .../main/java/btools/mapcreator/OsmNodeP.java | 151 +------------ .../btools/mapcreator/RelationMerger.java | 4 +- .../java/btools/mapcreator/WayLinker.java | 13 +- .../java/btools/mapaccess/NodesCache.java | 4 +- .../main/java/btools/mapaccess/OsmFile.java | 5 - .../main/java/btools/mapaccess/OsmLink.java | 17 +- .../main/java/btools/mapaccess/OsmNode.java | 203 +----------------- .../btools/mapaccess/OsmTransferNode.java | 129 ----------- .../java/btools/memrouter/GraphLoader.java | 2 +- .../btools/memrouter/ScheduledRouter.java | 4 +- .../main/java/btools/util/StackSampler.java | 148 +++++++++++++ 22 files changed, 234 insertions(+), 802 deletions(-) delete mode 100644 brouter-codec/src/main/java/btools/codec/MicroCache1.java delete mode 100644 brouter-core/src/main/java/btools/router/RoutingMessageHandler.java delete mode 100644 brouter-expressions/src/main/java/btools/expressions/BExpressionReceiver.java create mode 100644 brouter-util/src/main/java/btools/util/StackSampler.java diff --git a/brouter-codec/src/main/java/btools/codec/MicroCache1.java b/brouter-codec/src/main/java/btools/codec/MicroCache1.java deleted file mode 100644 index 9e13d07..0000000 --- a/brouter-codec/src/main/java/btools/codec/MicroCache1.java +++ /dev/null @@ -1,99 +0,0 @@ -package btools.codec; - -import btools.util.ByteDataWriter; - -/** - * MicroCache1 is the old data format as of brouter 1.1 that does not allow to - * filter out unaccessable nodes at the beginning of the cache pipeline - * - * Kept for backward compatibility - */ -public final class MicroCache1 extends MicroCache -{ - private int lonIdxBase; - private int latIdxBase; - - public MicroCache1( int size, byte[] databuffer, int lonIdx80, int latIdx80 ) throws Exception - { - super( databuffer ); // sets ab=databuffer, aboffset=0 - faid = new int[size]; - fapos = new int[size]; - this.size = 0; - lonIdxBase = ( lonIdx80 / 5 ) * 62500 + 31250; - latIdxBase = ( latIdx80 / 5 ) * 62500 + 31250; - } - - public MicroCache1( byte[] databuffer, int lonIdx80, int latIdx80 ) throws Exception - { - super( databuffer ); // sets ab=databuffer, aboffset=0 - lonIdxBase = ( lonIdx80 / 5 ) * 62500 + 31250; - latIdxBase = ( latIdx80 / 5 ) * 62500 + 31250; - - size = readInt(); - - // get net size - int nbytes = 0; - for ( int i = 0; i < size; i++ ) - { - aboffset += 4; - int bodySize = readVarLengthUnsigned(); - aboffset += bodySize; - nbytes += bodySize; - } - - // new array with only net data - byte[] nab = new byte[nbytes]; - aboffset = 4; - int noffset = 0; - faid = new int[size]; - fapos = new int[size]; - - for ( int i = 0; i < size; i++ ) - { - faid[i] = readInt() ^ 0x8000; // flip lat-sign for correct ordering - - int bodySize = readVarLengthUnsigned(); - System.arraycopy( ab, aboffset, nab, noffset, bodySize ); - aboffset += bodySize; - noffset += bodySize; - fapos[i] = noffset; - } - - ab = nab; - aboffset = noffset; - init( size ); - } - - @Override - public long expandId( int id32 ) - { - int lon32 = lonIdxBase + (short) ( id32 >> 16 ); - int lat32 = latIdxBase + (short) ( ( id32 & 0xffff ) ^ 0x8000 ); - return ( (long) lon32 ) << 32 | lat32; - } - - @Override - public int shrinkId( long id64 ) - { - int lon32 = (int) ( id64 >> 32 ); - int lat32 = (int) ( id64 & 0xffffffff ); - return ( lon32 - lonIdxBase ) << 16 | ( ( ( lat32 - latIdxBase ) & 0xffff ) ^ 0x8000 ); - } - - @Override - public int encodeMicroCache( byte[] buffer ) - { - ByteDataWriter dos = new ByteDataWriter( buffer ); - dos.writeInt( size ); - for ( int n = 0; n < size; n++ ) - { - dos.writeInt( faid[n] ^ 0x8000 ); - int start = n > 0 ? fapos[n - 1] : 0; - int end = fapos[n]; - int len = end - start; - dos.writeVarLengthUnsigned( len ); - dos.write( ab, start, len ); - } - return dos.size(); - } -} diff --git a/brouter-core/src/main/java/btools/router/OsmPath.java b/brouter-core/src/main/java/btools/router/OsmPath.java index d5bb08d..0696a2d 100644 --- a/brouter-core/src/main/java/btools/router/OsmPath.java +++ b/brouter-core/src/main/java/btools/router/OsmPath.java @@ -108,10 +108,11 @@ final class OsmPath implements OsmLinkHolder private void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc ) { - if ( link.descriptionBitmap == null ) throw new IllegalArgumentException( "null description for: " + link ); + byte[] description = link.descriptionBitmap; + if ( description == null ) throw new IllegalArgumentException( "null description for: " + link ); - boolean recordTransferNodes = detailMode || rc.countTraffic; - boolean recordMessageData = detailMode; + boolean recordTransferNodes = detailMode || rc.countTraffic; + boolean recordMessageData = detailMode; rc.nogomatch = false; @@ -126,7 +127,7 @@ final class OsmPath implements OsmLinkHolder int linkdisttotal = 0; - MessageData msgData = new MessageData(); + MessageData msgData = recordMessageData ? new MessageData() : null; OsmTransferNode transferNode = link.decodeFirsttransfer( p1 ); OsmNode targetNode = link.targetNode; @@ -138,27 +139,21 @@ final class OsmPath implements OsmLinkHolder int lon2; int lat2; short ele2; - byte[] description; if ( transferNode == null ) { lon2 = targetNode.ilon; lat2 = targetNode.ilat; ele2 = targetNode.selev; - description = link.descriptionBitmap; - if ( description == null ) throw new IllegalArgumentException( "null description for class: " + link.getClass() ); } else { lon2 = transferNode.ilon; lat2 = transferNode.ilat; ele2 = transferNode.selev; - description = transferNode.descriptionBitmap; - if ( description == null ) throw new IllegalArgumentException( "null description for class: " + transferNode.getClass() + "/" + link.getClass() + " counterlinkwritten=" + link.counterLinkWritten ); } - rc.messageHandler.setCurrentPos( lon2, lat2 ); - boolean sameData = rc.expctxWay.evaluate( rc.inverseDirection ^ link.counterLinkWritten, description, rc.messageHandler ); + boolean sameData = rc.expctxWay.evaluate( rc.inverseDirection ^ link.counterLinkWritten, description ); // if way description changed, store message if ( recordMessageData && msgData.wayKeyValues != null ) @@ -198,7 +193,10 @@ final class OsmPath implements OsmLinkHolder } } - msgData.linkdist += dist; + if ( recordMessageData ) + { + msgData.linkdist += dist; + } linkdisttotal += dist; boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f; @@ -210,9 +208,9 @@ final class OsmPath implements OsmLinkHolder double cos = rc.calcCosAngle( lon0, lat0, lon1, lat1, lon2, lat2 ); int turncost = (int)(cos * rc.expctxWay.getTurncost() + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty cost += turncost; - msgData.linkturncost += turncost; if ( recordMessageData ) { + msgData.linkturncost += turncost; msgData.turnangle = (float)rc.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 ); } } @@ -250,7 +248,10 @@ final class OsmPath implements OsmLinkHolder { int elevationCost = reduce/rc.downhillcostdiv; cost += elevationCost; - msgData.linkelevationcost += elevationCost; + if ( recordMessageData ) + { + msgData.linkelevationcost += elevationCost; + } } } else if ( ehbd < 0 ) @@ -280,7 +281,10 @@ final class OsmPath implements OsmLinkHolder { int elevationCost = reduce/rc.uphillcostdiv; cost += elevationCost; - msgData.linkelevationcost += elevationCost; + if ( recordMessageData ) + { + msgData.linkelevationcost += elevationCost; + } } } else if ( ehbu < 0 ) @@ -313,6 +317,7 @@ final class OsmPath implements OsmLinkHolder cost += waycost; // calculate traffic + if ( rc.countTraffic ) { int minDist = (int)rc.trafficSourceMinDist; int cost2 = cost < minDist ? minDist : cost; @@ -330,7 +335,10 @@ final class OsmPath implements OsmLinkHolder lastClassifier = newClassifier; float initialcost = rc.expctxWay.getInitialcost(); int iicost = (int)initialcost; - msgData.linkinitcost += iicost; + if ( recordMessageData ) + { + msgData.linkinitcost += iicost; + } cost += iicost; } @@ -402,8 +410,7 @@ final class OsmPath implements OsmLinkHolder if ( targetNode.nodeDescription != null ) { boolean nodeAccessGranted = rc.expctxWay.getNodeAccessGranted() != 0.; - rc.messageHandler.setCurrentPos( targetNode.ilon, targetNode.ilat ); - rc.expctxNode.evaluate( nodeAccessGranted , targetNode.nodeDescription, rc.messageHandler ); + rc.expctxNode.evaluate( nodeAccessGranted , targetNode.nodeDescription ); float initialcost = rc.expctxNode.getInitialcost(); if ( initialcost >= 1000000. ) { @@ -411,12 +418,12 @@ final class OsmPath implements OsmLinkHolder return; } int iicost = (int)initialcost; - msgData.linknodecost += iicost; cost += iicost; if ( recordMessageData ) { + msgData.linknodecost += iicost; msgData.nodeKeyValues = rc.expctxNode.getKeyValueDescription( nodeAccessGranted, targetNode.nodeDescription ); } } diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java index 2f444c4..f494aa5 100644 --- a/brouter-core/src/main/java/btools/router/RoutingContext.java +++ b/brouter-core/src/main/java/btools/router/RoutingContext.java @@ -111,8 +111,6 @@ public final class RoutingContext implements DistanceChecker turnInstructionRoundabouts = expctxGlobal.getVariableValue( "turnInstructionRoundabouts", 1.f ) != 0.f; } - public RoutingMessageHandler messageHandler = new RoutingMessageHandler(); - public List nogopoints = null; private List keepnogopoints = null; @@ -222,10 +220,11 @@ public final class RoutingContext implements DistanceChecker shortestmatch = false; - if ( d > 0. && nogopoints != null ) + if ( nogopoints != null && !nogopoints.isEmpty() && d > 0. ) { - for( OsmNodeNamed nogo : nogopoints ) + for( int ngidx = 0; ngidx < nogopoints.size(); ngidx++ ) { + OsmNodeNamed nogo = nogopoints.get(ngidx); double x1 = (lon1 - nogo.ilon) * coslat6; double y1 = (lat1 - nogo.ilat) * 0.000001; double x2 = (lon2 - nogo.ilon) * coslat6; diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java index ceb47f5..13e29f3 100644 --- a/brouter-core/src/main/java/btools/router/RoutingEngine.java +++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java @@ -16,6 +16,7 @@ import btools.mapaccess.OsmLinkHolder; import btools.mapaccess.OsmNode; import btools.mapaccess.OsmNodesMap; import btools.util.SortedHeap; +import btools.util.StackSampler; public class RoutingEngine extends Thread { @@ -43,6 +44,7 @@ public class RoutingEngine extends Thread private String logfileBase; private boolean infoLogEnabled; private Writer infoLogWriter; + private StackSampler stackSampler; protected RoutingContext routingContext; public double airDistanceCostFactor; @@ -66,9 +68,10 @@ public class RoutingEngine extends Thread this.infoLogEnabled = outfileBase != null; this.routingContext = rc; + File baseFolder = new File( routingContext.localFunction ).getParentFile().getParentFile(); try { - File debugLog = new File( new File( routingContext.localFunction ).getParentFile(), "../debug.txt" ); + File debugLog = new File( baseFolder, "debug.txt" ); if ( debugLog.exists() ) { infoLogWriter = new FileWriter( debugLog, true ); @@ -80,6 +83,15 @@ public class RoutingEngine extends Thread { throw new RuntimeException( "cannot open debug-log:" + ioe ); } + + File stackLog = new File( baseFolder, "stacks.txt" ); + if ( stackLog.exists() ) + { + stackSampler = new StackSampler( stackLog, 1000 ); + stackSampler.start(); + logInfo( "********** started stacksampling" ); + } + boolean cachedProfile = ProfileCache.parseProfile( rc ); if ( hasInfo() ) { @@ -229,6 +241,13 @@ public class RoutingEngine extends Thread try { infoLogWriter.close(); } catch( Exception e ) {} infoLogWriter = null; } + + if ( stackSampler != null ) + { + try { stackSampler.close(); } catch( Exception e ) {} + stackSampler = null; + } + } } @@ -378,16 +397,6 @@ public class RoutingEngine extends Thread { preloadPosition( mwp.waypoint ); } - - // preliminary-hack: use old stuff if not yet matched - for( int i=0; i nodeList = nodesCache.getAllNodes(); - - MatchedWaypoint mwp = new MatchedWaypoint(); - mwp.waypoint = wp; - - // first loop just to expand reverse links - for( OsmNode n : nodeList ) - { - if ( !nodesCache.obtainNonHollowNode( n ) ) - { - continue; - } - expandHollowLinkTargets( n ); - OsmLink startLink = new OsmLink(); - startLink.targetNode = n; - OsmPath startPath = new OsmPath( startLink ); - startLink.addLinkHolder( startPath ); - for( OsmLink link = n.firstlink; link != null; link = link.next ) - { - if ( link.descriptionBitmap == null ) continue; // reverse link not found - OsmNode nextNode = link.targetNode; - if ( nextNode.isHollow() ) continue; // border node? - if ( nextNode.firstlink == null ) continue; // don't care about dead ends - if ( nextNode == n ) continue; // ? - double oldRadius = wp.radius; - OsmPath testPath = new OsmPath( n, startPath, link, null, false, routingContext ); - if ( wp.radius < oldRadius ) - { - if ( testPath.cost < 0 ) - { - wp.radius = oldRadius; // no valid way - } - else - { - mwp.node1 = n; - mwp.node2 = nextNode; - mwp.radius = wp.radius; - mwp.crosspoint = new OsmNodeNamed(); - mwp.crosspoint.ilon = routingContext.ilonshortest; - mwp.crosspoint.ilat = routingContext.ilatshortest; - } - } - } - } - return mwp; - } // expand hollow link targets and resolve reverse links private void expandHollowLinkTargets( OsmNode n ) diff --git a/brouter-core/src/main/java/btools/router/RoutingMessageHandler.java b/brouter-core/src/main/java/btools/router/RoutingMessageHandler.java deleted file mode 100644 index 0d12100..0000000 --- a/brouter-core/src/main/java/btools/router/RoutingMessageHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Container for routig configs - * - * @author ab - */ -package btools.router; - -import btools.expressions.BExpressionReceiver; - -final class RoutingMessageHandler implements BExpressionReceiver -{ - private int ilon; - private int ilat; - - public void setCurrentPos( int lon, int lat) - { - ilon = lon; - ilat = lat; - } - - - @Override - public void expressionWarning( String context, String message ) - { - System.out.println( "message (lon=" + (ilon-180000000) + " lat=" + (ilat-90000000) - + " context " + context + "): " + message ); - } -} diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpression.java b/brouter-expressions/src/main/java/btools/expressions/BExpression.java index f41b8b3..9fb9725 100644 --- a/brouter-expressions/src/main/java/btools/expressions/BExpression.java +++ b/brouter-expressions/src/main/java/btools/expressions/BExpression.java @@ -25,8 +25,6 @@ final class BExpression private static final int NUMBER_EXP = 33; private static final int VARIABLE_EXP = 34; - private static final int DUMPPOS_EXP = 40; - private int typ; private BExpression op1; private BExpression op2; @@ -147,10 +145,6 @@ final class BExpression { exp.typ = NOT_EXP; } - else if ( "dumppos".equals( operator ) ) - { - exp.typ = DUMPPOS_EXP; - } else { nops = 0; // check elemantary expressions @@ -263,7 +257,6 @@ final class BExpression case NUMBER_EXP: return numberValue; case VARIABLE_EXP: return ctx.getVariableValue( variableIdx ); case NOT_EXP: return op1.evaluate(ctx) == 0.f ? 1.f : 0.f; - case DUMPPOS_EXP: ctx.expressionWarning( "INFO" ); return op1.evaluate(ctx); default: throw new IllegalArgumentException( "unknown op-code: " + typ ); } } diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java index 553e0b5..1850044 100644 --- a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java +++ b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java @@ -31,8 +31,6 @@ public abstract class BExpressionContext private BufferedReader _br = null; private boolean _readerDone = false; - private BExpressionReceiver _receiver; - private Map lookupNumbers = new HashMap(); private ArrayList lookupValues = new ArrayList(); private ArrayList lookupNames = new ArrayList(); @@ -58,20 +56,21 @@ public abstract class BExpressionContext private byte[] currentByteArray = null; private boolean currentInverseDirection= false; - public List expressionList; + private List expressionList; private int minWriteIdx; // build-in variable indexes for fast access private int[] buildInVariableIdx; - protected float[][] arrayBuildInVariablesCache; + private float[][] arrayBuildInVariablesCache; + private float[] hashBucketVars; abstract String[] getBuildInVariableNames(); - protected float getBuildInVariable( int idx ) + protected final float getBuildInVariable( int idx ) { - return arrayBuildInVariablesCache[idx][currentHashBucket]; + return hashBucketVars[idx]; } private int linenr; @@ -105,10 +104,10 @@ public abstract class BExpressionContext // create the build-in variables cache int nBuildInVars = getBuildInVariableNames().length; - arrayBuildInVariablesCache = new float[nBuildInVars][]; - for( int vi=0; vi= 9999.f ) { - evaluate( true, description, null ); + evaluate( true, description ); float reverseCostFactor = getCostfactor(); if ( reverseCostFactor < minCostFactor ) { diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpressionReceiver.java b/brouter-expressions/src/main/java/btools/expressions/BExpressionReceiver.java deleted file mode 100644 index 57b44f6..0000000 --- a/brouter-expressions/src/main/java/btools/expressions/BExpressionReceiver.java +++ /dev/null @@ -1,7 +0,0 @@ -package btools.expressions; - - -public interface BExpressionReceiver -{ - public void expressionWarning( String context, String message ); -} diff --git a/brouter-expressions/src/test/java/btools/expressions/EncodeDecodeTest.java b/brouter-expressions/src/test/java/btools/expressions/EncodeDecodeTest.java index 09f90ef..b32f604 100644 --- a/brouter-expressions/src/test/java/btools/expressions/EncodeDecodeTest.java +++ b/brouter-expressions/src/test/java/btools/expressions/EncodeDecodeTest.java @@ -39,7 +39,7 @@ public class EncodeDecodeTest byte[] description = expctxWay.encode(lookupData); // calculate the cost factor from that description - expctxWay.evaluate( false, description, null ); + expctxWay.evaluate( false, description ); float costfactor = expctxWay.getCostfactor(); Assert.assertTrue( "costfactor mismatch", Math.abs( costfactor - 5.15 ) < 0.00001 ); diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/OsmCutter.java b/brouter-map-creator/src/main/java/btools/mapcreator/OsmCutter.java index 375d5f7..dd42fcd 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/OsmCutter.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/OsmCutter.java @@ -156,9 +156,9 @@ public class OsmCutter extends MapCreatorBase if ( w.description == null ) return; // filter according to profile - _expctxWay.evaluate( false, w.description, null ); + _expctxWay.evaluate( false, w.description ); boolean ok = _expctxWay.getCostfactor() < 10000.; - _expctxWay.evaluate( true, w.description, null ); + _expctxWay.evaluate( true, w.description ); ok |= _expctxWay.getCostfactor() < 10000.; if ( !ok ) return; diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodeP.java b/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodeP.java index b1582e2..5621d6e 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodeP.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/OsmNodeP.java @@ -10,18 +10,10 @@ import java.util.ArrayList; import java.util.HashMap; import btools.codec.MicroCache; -import btools.codec.MicroCache1; import btools.codec.MicroCache2; public class OsmNodeP extends OsmLinkP { - public static final int SIGNLON_BITMASK = 0x80; - public static final int SIGNLAT_BITMASK = 0x40; - public static final int TRANSFERNODE_BITMASK = 0x20; - public static final int WRITEDESC_BITMASK = 0x10; - public static final int SKIPDETAILS_BITMASK = 0x08; - public static final int NODEDESC_BITMASK = 0x04; - /** * The latitude */ @@ -104,151 +96,10 @@ public class OsmNodeP extends OsmLinkP return null; } - public void writeNodeData1( MicroCache1 mc ) throws IOException - { - mc.writeShort( getSElev() ); - - // hack: write node-desc as link tag (copy cycleway-bits) - byte[] nodeDescription = getNodeDecsription(); - - for ( OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext( this ) ) - { - int ilonref = ilon; - int ilatref = ilat; - - OsmLinkP link = link0; - OsmNodeP origin = this; - int skipDetailBit = link0.descriptionBitmap == null ? SKIPDETAILS_BITMASK : 0; - - // first pass just to see if that link is consistent - while (link != null) - { - OsmNodeP target = link.getTarget( origin ); - if ( !target.isTransferNode() ) - { - break; - } - // next link is the one (of two), does does'nt point back - for ( link = target.getFirstLink(); link != null; link = link.getNext( target ) ) - { - if ( link.getTarget( target ) != origin ) - break; - } - origin = target; - } - if ( link == null ) - continue; // dead end - - if ( skipDetailBit == 0 ) - { - link = link0; - origin = this; - } - byte[] lastDescription = null; - while (link != null) - { - if ( link.descriptionBitmap == null && skipDetailBit == 0 ) - throw new IllegalArgumentException( "missing way description..." ); - - OsmNodeP target = link.getTarget( origin ); - int tranferbit = target.isTransferNode() ? TRANSFERNODE_BITMASK : 0; - int nodedescbit = nodeDescription != null ? NODEDESC_BITMASK : 0; - - int writedescbit = 0; - if ( skipDetailBit == 0 ) // check if description changed - { - int inverseBitByteIndex = 0; - boolean inverseDirection = link.isReverse( origin ); - byte[] ab = link.descriptionBitmap; - int abLen = ab.length; - int lastLen = lastDescription == null ? 0 : lastDescription.length; - boolean equalsCurrent = abLen == lastLen; - if ( equalsCurrent ) - { - for ( int i = 0; i < abLen; i++ ) - { - byte b = ab[i]; - if ( i == inverseBitByteIndex && inverseDirection ) - b ^= 1; - if ( b != lastDescription[i] ) - { - equalsCurrent = false; - break; - } - } - } - if ( !equalsCurrent ) - { - writedescbit = WRITEDESC_BITMASK; - lastDescription = new byte[abLen]; - System.arraycopy( ab, 0, lastDescription, 0, abLen ); - if ( inverseDirection ) - lastDescription[inverseBitByteIndex] ^= 1; - } - - } - - int bm = tranferbit | writedescbit | nodedescbit | skipDetailBit; - int dlon = target.ilon - ilonref; - int dlat = target.ilat - ilatref; - ilonref = target.ilon; - ilatref = target.ilat; - if ( dlon < 0 ) - { - bm |= SIGNLON_BITMASK; - dlon = -dlon; - } - if ( dlat < 0 ) - { - bm |= SIGNLAT_BITMASK; - dlat = -dlat; - } - mc.writeByte( bm ); - - mc.writeVarLengthUnsigned( dlon ); - mc.writeVarLengthUnsigned( dlat ); - - if ( writedescbit != 0 ) - { - // write the way description, code direction into the first bit - mc.writeByte( lastDescription.length ); - mc.write( lastDescription ); - } - if ( nodedescbit != 0 ) - { - mc.writeByte( nodeDescription.length ); - mc.write( nodeDescription ); - nodeDescription = null; - } - - link.descriptionBitmap = null; // mark link as written - - if ( tranferbit == 0 ) - { - break; - } - mc.writeVarLengthSigned( target.getSElev() - getSElev() ); - // next link is the one (of two), does does'nt point back - for ( link = target.getFirstLink(); link != null; link = link.getNext( target ) ) - { - if ( link.getTarget( target ) != origin ) - break; - } - if ( link == null ) - throw new RuntimeException( "follow-up link not found for transfer-node!" ); - origin = target; - } - } - } - public void writeNodeData( MicroCache mc ) throws IOException { boolean valid = true; - if ( mc instanceof MicroCache1 ) - { - writeNodeData1( (MicroCache1) mc ); - } - else if ( mc instanceof MicroCache2 ) + if ( mc instanceof MicroCache2 ) { valid = writeNodeData2( (MicroCache2) mc ); } diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/RelationMerger.java b/brouter-map-creator/src/main/java/btools/mapcreator/RelationMerger.java index c85eb2b..70a5072 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/RelationMerger.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/RelationMerger.java @@ -124,11 +124,11 @@ public class RelationMerger extends MapCreatorBase { boolean ok = true; // check access and log a warning for conflicts - expctxReport.evaluate( false, data.description, null ); + expctxReport.evaluate( false, data.description ); boolean warn = expctxReport.getCostfactor() >= 10000.; if ( warn ) { - expctxCheck.evaluate( false, data.description, null ); + expctxCheck.evaluate( false, data.description ); ok = expctxCheck.getCostfactor() < 10000.; System.out.println( "** relation access conflict for wid = " + data.wid + " tags:" + expctxReport.getKeyValueDescription( false, data.description ) + " (ok=" + ok + ")" ); diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/WayLinker.java b/brouter-map-creator/src/main/java/btools/mapcreator/WayLinker.java index a508342..e77d116 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/WayLinker.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/WayLinker.java @@ -9,7 +9,6 @@ import java.util.TreeMap; import btools.codec.DataBuffers; import btools.codec.MicroCache; -import btools.codec.MicroCache1; import btools.codec.MicroCache2; import btools.codec.StatCoderContext; import btools.expressions.BExpressionContextWay; @@ -57,7 +56,7 @@ public class WayLinker extends MapCreatorBase private int minLat; private int microCacheEncoding = 2; - private int divisor = microCacheEncoding == 2 ? 32 : 80; + private int divisor = 32; private int cellsize = 1000000 / divisor; private void reset() @@ -186,9 +185,9 @@ public class WayLinker extends MapCreatorBase int lastTraffic = 0; // filter according to profile - expctxWay.evaluate( false, description, null ); + expctxWay.evaluate( false, description ); boolean ok = expctxWay.getCostfactor() < 10000.; - expctxWay.evaluate( true, description, null ); + expctxWay.evaluate( true, description ); ok |= expctxWay.getCostfactor() < 10000.; if ( !ok ) return; @@ -330,8 +329,7 @@ public class WayLinker extends MapCreatorBase OsmNodeP n0 = subList.get( 0 ); int lonIdxDiv = n0.ilon / cellsize; int latIdxDiv = n0.ilat / cellsize; - MicroCache mc = microCacheEncoding == 0 ? new MicroCache1( size, abBuf2, lonIdxDiv, latIdxDiv ) : new MicroCache2( size, abBuf2, - lonIdxDiv, latIdxDiv, divisor ); + MicroCache mc = new MicroCache2( size, abBuf2, lonIdxDiv, latIdxDiv, divisor ); // sort via treemap TreeMap sortedList = new TreeMap(); @@ -360,8 +358,7 @@ public class WayLinker extends MapCreatorBase System.arraycopy( abBuf1, 0, subBytes, 0, len ); // cross-check the encoding: re-instantiate the cache - MicroCache mc2 = microCacheEncoding == 0 ? new MicroCache1( subBytes, lonIdxDiv, latIdxDiv ) : new MicroCache2( new DataBuffers( - subBytes ), lonIdxDiv, latIdxDiv, divisor, null, null ); + MicroCache mc2 = new MicroCache2( new DataBuffers( subBytes ), lonIdxDiv, latIdxDiv, divisor, null, null ); // ..and check if still the same String diffMessage = mc.compareWith( mc2 ); if ( diffMessage != null ) diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java b/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java index e0fbc07..58784d2 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java @@ -35,8 +35,6 @@ public final class NodesCache private OsmFile[][] fileRows; private ArrayList segmentList = new ArrayList(); - public DistanceChecker distanceChecker; - public WaypointMatcher waypointMatcher; public boolean first_file_access_failed = false; @@ -212,7 +210,7 @@ public final class NodesCache long id = node.getIdFromPos(); if ( segment.getAndClear( id ) ) { - node.parseNodeBody( segment, nodesMap, distanceChecker ); + node.parseNodeBody( segment, nodesMap ); } if ( garbageCollectionEnabled ) // garbage collection diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java index 567b453..94ca165 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java @@ -10,7 +10,6 @@ import java.io.RandomAccessFile; import btools.codec.DataBuffers; import btools.codec.MicroCache; -import btools.codec.MicroCache1; import btools.codec.MicroCache2; import btools.codec.TagValueValidator; import btools.codec.WaypointMatcher; @@ -152,10 +151,6 @@ final class OsmFile int crcData = Crc32.crc( ab, 0, asize - 4 ); int crcFooter = new ByteDataReader( ab, asize - 4 ).readInt(); - if ( crcData == crcFooter ) - { - return reallyDecode ? new MicroCache1( ab, lonIdx, latIdx ) : null; - } if ( ( crcData ^ 2 ) == crcFooter ) { return reallyDecode ? new MicroCache2( dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher ) : null; diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmLink.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmLink.java index b967251..63d4fd2 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmLink.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmLink.java @@ -26,21 +26,17 @@ public class OsmLink public boolean counterLinkWritten; - public boolean hasNewGeometry; // preliminary - public byte state; public void setGeometry( byte[] geometry ) { this.geometry = geometry; - hasNewGeometry = true; } final public OsmTransferNode decodeFirsttransfer( OsmNode sourceNode ) { - if ( geometry == null ) return null; - if ( hasNewGeometry ) - { + if ( geometry == null ) return null; + OsmTransferNode firstTransferNode = null; OsmTransferNode lastTransferNode = null; OsmNode startnode = counterLinkWritten ? targetNode : sourceNode; @@ -53,7 +49,6 @@ public class OsmLink OsmTransferNode trans = new OsmTransferNode(); trans.ilon = olon + r.readVarLengthSigned(); trans.ilat = olat + r.readVarLengthSigned(); - trans.descriptionBitmap = descriptionBitmap; trans.selev = (short)(oselev + r.readVarLengthSigned()); olon = trans.ilon; olat = trans.ilat; @@ -77,14 +72,6 @@ public class OsmLink } } return firstTransferNode; - } - return OsmTransferNode.decode( geometry ); - } - - final public void encodeFirsttransfer( OsmTransferNode firsttransfer ) - { - if ( firsttransfer == null ) geometry = null; - else geometry = OsmTransferNode.encode( firsttransfer ); } final public void addLinkHolder( OsmLinkHolder holder ) diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java index 3a0b982..6aa9ebc 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java @@ -6,22 +6,11 @@ package btools.mapaccess; import btools.codec.MicroCache; -import btools.codec.MicroCache1; import btools.codec.MicroCache2; import btools.util.ByteArrayUnifier; public class OsmNode implements OsmPos { - public static final int EXTERNAL_BITMASK = 0x80; // old semantic - public static final int SIGNLON_BITMASK = 0x80; - public static final int SIGNLAT_BITMASK = 0x40; - public static final int TRANSFERNODE_BITMASK = 0x20; - public static final int WRITEDESC_BITMASK = 0x10; - public static final int SKIPDETAILS_BITMASK = 0x08; - public static final int NODEDESC_BITMASK = 0x04; - public static final int RESERVED1_BITMASK = 0x02; - public static final int RESERVED2_BITMASK = 0x01; - public OsmNode() { } @@ -146,21 +135,17 @@ public class OsmNode implements OsmPos return "" + getIdFromPos(); } - public void parseNodeBody( MicroCache mc, OsmNodesMap hollowNodes, DistanceChecker dc ) + public void parseNodeBody( MicroCache mc, OsmNodesMap hollowNodes ) { - if ( mc instanceof MicroCache1 ) + if ( mc instanceof MicroCache2 ) { - parseNodeBody1( (MicroCache1) mc, hollowNodes, dc ); - } - else if ( mc instanceof MicroCache2 ) - { - parseNodeBody2( (MicroCache2) mc, hollowNodes, dc ); + parseNodeBody2( (MicroCache2) mc, hollowNodes ); } else throw new IllegalArgumentException( "unknown cache version: " + mc.getClass() ); } - public void parseNodeBody2( MicroCache2 mc, OsmNodesMap hollowNodes, DistanceChecker dc ) + public void parseNodeBody2( MicroCache2 mc, OsmNodesMap hollowNodes ) { ByteArrayUnifier abUnifier = hollowNodes.getByteArrayUnifier(); @@ -184,10 +169,6 @@ public class OsmNode implements OsmPos } byte[] geometry = mc.readDataUntil( endPointer ); - // preliminary hack: way-point-matching not here (done at decoding time) - if ( dc != null ) - continue; - if ( linklon == ilon && linklat == ilat ) { continue; // skip self-ref @@ -236,186 +217,10 @@ public class OsmNode implements OsmPos rlink.setGeometry( geometry ); } } - } hollowNodes.remove( this ); } - public void parseNodeBody1( MicroCache1 is, OsmNodesMap hollowNodes, DistanceChecker dc ) - { - ByteArrayUnifier abUnifier = hollowNodes.getByteArrayUnifier(); - - selev = is.readShort(); - - while (is.hasMoreData()) - { - int ilonref = ilon; - int ilatref = ilat; - - boolean counterLinkWritten = false; - OsmTransferNode firstTransferNode = null; - OsmTransferNode lastTransferNode = null; - int linklon; - int linklat; - byte[] description = null; - for ( ;; ) - { - int bitField = is.readByte(); - int dlon = is.readVarLengthUnsigned(); - int dlat = is.readVarLengthUnsigned(); - if ( ( bitField & SIGNLON_BITMASK ) != 0 ) - { - dlon = -dlon; - } - if ( ( bitField & SIGNLAT_BITMASK ) != 0 ) - { - dlat = -dlat; - } - linklon = ilonref + dlon; - linklat = ilatref + dlat; - ilonref = linklon; - ilatref = linklat; - // read variable length or old 8 byte fixed, and ensure that 8 bytes is - // only fixed - if ( ( bitField & WRITEDESC_BITMASK ) != 0 ) - { - byte[] ab = new byte[is.readByte()]; - is.readFully( ab ); - description = abUnifier.unify( ab ); - } - if ( ( bitField & NODEDESC_BITMASK ) != 0 ) - { - byte[] ab = new byte[is.readByte()]; - is.readFully( ab ); - nodeDescription = abUnifier.unify( ab ); - } - if ( ( bitField & RESERVED1_BITMASK ) != 0 ) - { - byte[] ab = new byte[is.readByte()]; - is.readFully( ab ); - } - if ( ( bitField & RESERVED2_BITMASK ) != 0 ) - { - byte[] ab = new byte[is.readByte()]; - is.readFully( ab ); - } - if ( ( bitField & SKIPDETAILS_BITMASK ) != 0 ) - { - counterLinkWritten = true; - } - - if ( description == null && !counterLinkWritten ) - throw new IllegalArgumentException( "internal error: missing way description!" ); - - boolean isTransfer = ( bitField & TRANSFERNODE_BITMASK ) != 0; - if ( isTransfer ) - { - OsmTransferNode trans = new OsmTransferNode(); - trans.ilon = linklon; - trans.ilat = linklat; - trans.descriptionBitmap = description; - trans.selev = (short) ( selev + is.readVarLengthSigned() ); - if ( lastTransferNode == null ) - { - firstTransferNode = trans; - } - else - { - lastTransferNode.next = trans; - } - lastTransferNode = trans; - } - else - { - break; - } - } - - // performance shortcut: ignore link if out of reach - if ( dc != null && !counterLinkWritten ) - { - if ( !dc.isWithinRadius( ilon, ilat, firstTransferNode, linklon, linklat ) ) - { - continue; - } - } - - if ( linklon == ilon && linklat == ilat ) - { - continue; // skip self-ref - } - - // first check the known links for that target - OsmLink link = getCompatibleLink( linklon, linklat, counterLinkWritten, 2 ); - if ( link == null ) // .. not found, then check the hollow nodes - { - long targetNodeId = ( (long) linklon ) << 32 | linklat; - OsmNode tn = hollowNodes.get( targetNodeId ); // target node - if ( tn == null ) // node not yet known, create a new hollow proxy - { - tn = new OsmNode( linklon, linklat ); - tn.setHollow(); - hollowNodes.put( tn ); - } - link = new OsmLink(); - link.targetNode = tn; - link.counterLinkWritten = counterLinkWritten; - link.state = 1; - addLink( link ); - } - - // now we have a link with a target node -> get the reverse link - OsmLink rlink = link.targetNode.getCompatibleLink( ilon, ilat, !counterLinkWritten, 1 ); - if ( rlink == null ) // .. not found, create it - { - rlink = new OsmLink(); - rlink.targetNode = this; - rlink.counterLinkWritten = !counterLinkWritten; - rlink.state = 2; - link.targetNode.addLink( rlink ); - } - - if ( !counterLinkWritten ) - { - // we have the data for that link, so fill both the link .. - link.descriptionBitmap = description; - link.encodeFirsttransfer( firstTransferNode ); - - // .. and the reverse - if ( rlink.counterLinkWritten ) - { - rlink.descriptionBitmap = description; // default for no - // transfer-nodes - OsmTransferNode previous = null; - OsmTransferNode rtrans = null; - for ( OsmTransferNode trans = firstTransferNode; trans != null; trans = trans.next ) - { - if ( previous == null ) - { - rlink.descriptionBitmap = trans.descriptionBitmap; - } - else - { - previous.descriptionBitmap = trans.descriptionBitmap; - } - rtrans = new OsmTransferNode(); - rtrans.ilon = trans.ilon; - rtrans.ilat = trans.ilat; - rtrans.selev = trans.selev; - rtrans.next = previous; - rtrans.descriptionBitmap = description; - previous = rtrans; - } - rlink.encodeFirsttransfer( rtrans ); - } - } - - } - if ( dc == null ) - { - hollowNodes.remove( this ); - } - } public boolean isHollow() { diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmTransferNode.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmTransferNode.java index 50ad8e0..ac9ba1f 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmTransferNode.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmTransferNode.java @@ -5,144 +5,15 @@ */ package btools.mapaccess; -import btools.util.ByteDataReader; -import btools.util.ByteDataWriter; public final class OsmTransferNode { - /** - * The description bitmap is mainly the way description - * used to calculate the costfactor - */ - public byte[] descriptionBitmap; - public OsmTransferNode next; public int ilon; public int ilat; public short selev; - private static final int BIT_DESC = 1; - private static final int BIT_ILONHIGH = 2; - private static final int BIT_ILATHIGH = 4; - private static final int BIT_STOP = 8; - - // encode this transfer-node into a byte array - public static byte[] encode( OsmTransferNode tn ) - { - byte[] currentDesc = null; - int currentILonHigh = 0; - int currentILatHigh = 0; - OsmTransferNode n = tn; - - // first loop to calc size - int size = 1; // stop-bit - - while( n != null ) - { - if ( n.descriptionBitmap == null ) throw new IllegalArgumentException( "transfernode-encode: description is null" ); - - if( n.descriptionBitmap != currentDesc ) - { - currentDesc = n.descriptionBitmap; - size += 1 + currentDesc.length; - } - if( ( n.ilon >> 16 ) != currentILonHigh ) - { - size += 2; - currentILonHigh = n.ilon >> 16; - } - if( (n.ilat >> 16) != currentILatHigh ) - { - size += 2; - currentILatHigh = n.ilat >> 16; - } - size += 7; - n = n.next; - } - - byte[] ab = new byte[size]; - ByteDataWriter os = new ByteDataWriter( ab ); - - currentDesc = null; - currentILonHigh = 0; - currentILatHigh = 0; - n = tn; - while( n != null ) - { - int mode = 0; - if( n.descriptionBitmap != currentDesc ) - { - mode |= BIT_DESC; - currentDesc = n.descriptionBitmap; - } - if( ( n.ilon >> 16 ) != currentILonHigh ) - { - mode |= BIT_ILONHIGH; - currentILonHigh = n.ilon >> 16; - } - if( (n.ilat >> 16) != currentILatHigh ) - { - mode |= BIT_ILATHIGH; - currentILatHigh = n.ilat >> 16; - } - os.writeByte( mode); - if ( (mode & BIT_DESC) != 0 ) { os.writeByte( currentDesc.length ); os.write( currentDesc ); } - if ( (mode & BIT_ILONHIGH) != 0 ) os.writeShort( currentILonHigh ); - if ( (mode & BIT_ILATHIGH) != 0 ) os.writeShort( currentILatHigh ); - os.writeShort( n.ilon ); - os.writeShort( n.ilat ); - os.writeShort( n.selev ); - n = n.next; - } - os.writeByte( BIT_STOP ); - return ab; - } - - // decode a transfer-node from a byte array - public static OsmTransferNode decode( byte[] ab ) - { - ByteDataReader is = new ByteDataReader( ab ); - - OsmTransferNode firstNode = null; - OsmTransferNode lastNode = null; - byte[] currentDesc = null; - int currentILonHigh = 0; - int currentILatHigh = 0; - - for(;;) - { - byte mode = is.readByte(); - if ( (mode & BIT_STOP ) != 0 ) break; - - OsmTransferNode n = new OsmTransferNode(); - if ( (mode & BIT_DESC) != 0 ) { int dlen = is.readByte(); currentDesc = new byte[dlen]; is.readFully( currentDesc ); } - if ( (mode & BIT_ILONHIGH) != 0 ) currentILonHigh = is.readShort(); - if ( (mode & BIT_ILATHIGH) != 0 ) currentILatHigh = is.readShort(); - n.descriptionBitmap = currentDesc; - if ( n.descriptionBitmap == null ) throw new IllegalArgumentException( "transfernode-decode: description is null" ); - int ilon = is.readShort() & 0xffff; ilon |= currentILonHigh << 16; - int ilat = is.readShort() & 0xffff; ilat |= currentILatHigh << 16; - n.ilon = ilon; - n.ilat = ilat; - n.selev = is.readShort(); - - if ( ilon != n.ilon ) System.out.println( "ilon=" + ilon + " n.ilon=" + n.ilon ); - if ( ilat != n.ilat ) System.out.println( "ilat=" + ilat + " n.ilat=" + n.ilat ); - - if ( lastNode != null ) - { - lastNode.next = n; - } - else - { - firstNode = n; - } - lastNode = n; - } - return firstNode; - } - } diff --git a/brouter-mem-router/src/main/java/btools/memrouter/GraphLoader.java b/brouter-mem-router/src/main/java/btools/memrouter/GraphLoader.java index 13b0c10..67f9c28 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/GraphLoader.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/GraphLoader.java @@ -198,7 +198,7 @@ public class GraphLoader extends MapCreatorBase { if ( link.isWayLink() ) { - wayCtx.evaluate( false, link.descriptionBitmap, null ); + wayCtx.evaluate( false, link.descriptionBitmap ); if ( wayCtx.getCostfactor() < 10000.f ) { return true; diff --git a/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java b/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java index ae88de7..3059f60 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java @@ -347,7 +347,7 @@ System.out.println( "*** finishedOffsets = " + finishedOffsets ); else if ( link.isWayLink() ) { // get costfactor - rc.expctxWay.evaluate( link.isReverse( currentNode ), link.descriptionBitmap, null ); + rc.expctxWay.evaluate( link.isReverse( currentNode ), link.descriptionBitmap ); // *** penalty for distance float costfactor = rc.expctxWay.getCostfactor(); @@ -366,7 +366,7 @@ System.out.println( "*** finishedOffsets = " + finishedOffsets ); if ( node.getNodeDecsription() != null ) { - rc.expctxNode.evaluate( rc.expctxWay.getNodeAccessGranted() != 0., node.getNodeDecsription(), null ); + rc.expctxNode.evaluate( rc.expctxWay.getNodeAccessGranted() != 0., node.getNodeDecsription() ); float initialcost = rc.expctxNode.getInitialcost(); if ( initialcost >= 1000000. ) { diff --git a/brouter-util/src/main/java/btools/util/StackSampler.java b/brouter-util/src/main/java/btools/util/StackSampler.java new file mode 100644 index 0000000..1c0f0b6 --- /dev/null +++ b/brouter-util/src/main/java/btools/util/StackSampler.java @@ -0,0 +1,148 @@ +package btools.util; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.Map; +import java.util.Random; + +public class StackSampler extends Thread +{ + private DateFormat df = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss,SSS", new Locale( "en", "US" ) ); + private BufferedWriter bw; + private Random rand = new Random(); + + private int interval; + private int flushCnt = 0; + + private volatile boolean stopped; + + public StackSampler( File logfile, int interval ) + { + this.interval = interval; + try + { + bw = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( logfile, true ) ) ); + } + catch (Exception e) + { + printError( "StackSampler: " + e.getMessage() ); + } + } + + protected void printError( String msg ) + { + System.out.println( msg ); + } + + @Override + public void run() + { + while( !stopped ) + { + dumpThreads(); + } + if ( bw != null ) + { + try + { + bw.close(); + } + catch( Exception e ) {} + } + } + + public void dumpThreads() + { + try + { + int wait1 = rand.nextInt( interval ); + int wait2 = interval - wait1; + Thread.sleep( wait1 ); + StringBuilder sb = new StringBuilder( df.format( new Date() ) + " THREADDUMP\n" ); + Map allThreads = Thread.getAllStackTraces(); + for ( Map.Entry e : allThreads.entrySet() ) + { + Thread t = e.getKey(); + if ( t == Thread.currentThread() ) + { + continue; // not me + } + + StackTraceElement[] stack = e.getValue(); + if ( !matchesFilter( stack ) ) + { + continue; + } + + sb.append( " (ID=" ).append( t.getId() ).append( " \"" ).append( t.getName() ).append( "\" " ).append( t.getState() ).append( "\n" ); + for ( StackTraceElement line : stack ) + { + sb.append( " " ).append( line.toString() ).append( "\n" ); + } + sb.append( "\n" ); + } + bw.write( sb.toString() ); + if ( flushCnt++ >= 0 ) + { + flushCnt = 0; + bw.flush(); + } + Thread.sleep( wait2 ); + } + catch (Exception e) + { + // ignore + } + } + + public void close() + { + stopped = true; + interrupt(); + } + + private boolean matchesFilter( StackTraceElement[] stack ) + { + boolean positiveMatch = false; + for ( StackTraceElement e : stack ) + { + String s = e.toString(); + if ( s.indexOf( "btools" ) >= 0 ) + { + positiveMatch = true; + } + if ( s.indexOf( "Thread.sleep" ) >= 0 ) + { + return false; + } + } + return positiveMatch; + } + + public static void main( String[] args ) throws Exception + { + System.out.println( "StackSampler..." ); + Class clazz = Class.forName( args[0] ); + String[] args2 = new String[args.length - 1]; + for ( int i = 1; i < args.length; i++ ) + { + args2[i - 1] = args[i]; + } + StackSampler t = new StackSampler( new File( "stacks.log" ), 1000 ); + t.start(); + try + { + clazz.getMethod( "main", String[].class ).invoke( null, new Object[]{ args2 } ); + } + finally + { + t.close(); + } + } +}