// $Id: ScoreKeeper.java,v 1.15 2007/11/07 08:56:27 zahorjan Exp $ import java.util.*; import java.io.*; /** * This class keeps track of scoring for the run. * The score is the average (per time step) of: *
 *  sum over all router table entries, everywhere of
 *    entries that correctly indicate a next hop that leads to the dest
 *    plus entries that say don't forward and no path exists
 *    minus entries that say forward but don't lead to the destination
 *    minus entries that say don't forward but a path exists
 *    minus (#update packets sent / (N*(N-1))
 * 
* where N is the number of nodes in the network. *

* It also keeps track of 'reachability,' defined as the fraction of all * (src,dst) pairs for which a path exists in the actual network that * are reachable using the router tables. (That is, if a (src,dst) pair * isn't reachable in the network, it doesn't count against this measure.) *

* Finally, it keeps track of 'availability,' which is simply the fraction * of all (src,dst) pairs that are reachable through the routing tables. * (This measure vaguely reflects the user experience - how much trouble * is caused by the combination of actual network partitions plus the * fact that routing tables are inaccurate.) */ public class ScoreKeeper { /** * Used by getScoreKeeper(). */ private static ScoreKeeper theScoreKeeper = null; /** * There can be only one ScoreKeeper object in a run. * Get it... */ public static ScoreKeeper getScoreKeeper() { return theScoreKeeper; } /** * Running sum of the number of reachable (src,dest) pairs. */ private int reachableCnt; /** * Running sum (across time steps) of the fraction of actually * reachable pairs that are reachable by the routing tables. */ private double sumFractionReachable; /** * Sum of the number of update packets sent (during this timestep, hopefully). */ private int updateCnt; /** * Sum of ratio of number of update packets sent each timestep to a baseline number. */ private double sumFractionUpdates; /** * Running sum of the number of correct routing table entries, * where correctness indicates they say 'don't route' and in fact * there is no path to dest or they say to route and the path * they begin reaches the dest. */ private double sumFractionCorrect; /** * Number of timestep samples recorded so far */ private int numTimestepSamples; /** * N*(N-1), where N is the number of nodes in the Network. * (It's a double because of how it will be used.) */ private double numNetworkPairs; /** * Used if creating a graph has been enabled in ConstAlg.java. */ private FileOutputStream dataOut = null; /** * This constructor does very little. Most of the initialization * is done in reset(), which must be called before this object is * usable. Note that reset() cannot be invoked * until a (the, in fact) Network object exists. */ ScoreKeeper() throws IOException { theScoreKeeper = this; } /** * Reset all acculated statistics to zero. *

* An exception will occur if this method is called before the * Network object has been created! */ public void reset() throws IOException { reachableCnt = 0; updateCnt = 0; numTimestepSamples = 0; sumFractionReachable = 0.0; sumFractionCorrect = 0.0; sumFractionUpdates = 0.0; // Here's where the exception would occur, if this method were // called too early. int nnodes = Network.getNetwork().numNodes(); numNetworkPairs = (double)(nnodes*(nnodes-1)); if ( dataOut != null ) dataOut.close(); if ( ConstConfig.WRITE_REACHABILITY_GRAPH ) { dataOut = new FileOutputStream("simgraph.data"); dataOut.write(("" + sim.getNumInitialFailures() + "\t" + nnodes + "\t" + Network.getNetwork().numEdges() + "\n").getBytes()); } } /** * Inform scorekeeper that an update packet is being sent. */ public void sentUpdate() { updateCnt++; } /** * Inform scorekeeper about reachability of a time step. */ public void reachabilitySample(int numReachable, int actualNumReachable, int nCorrect, int nActiveSamples ) throws IOException { reachableCnt += numReachable; double fracSample; if ( actualNumReachable > 0 ) fracSample = ((double)numReachable)/actualNumReachable; else fracSample = 1.0F; sumFractionReachable += fracSample; // write sample to a jgraph file, if enabled if ( dataOut != null ) { dataOut.write(("\t" + sim.getTime() + "\t" + fracSample + "\t" + (numReachable/numNetworkPairs) + "\n").getBytes()); //dataOut.flush(); } // update number correct sum sumFractionCorrect += ((double)nCorrect)/nActiveSamples; // tally what fraction of "baseline number of update packets" were actually sent. // the baseline allows one update packet from each non-failed node to each other non-failed node double nnodes = nActiveSamples / Network.getNetwork().numNodes(); sumFractionUpdates += ((double)updateCnt)/(nnodes*(nnodes-1.0)); updateCnt = 0; // update count of the number of timestep samples we've seen. numTimestepSamples++; } /** * Get current score. The score is (simplifying slightly) *

     *   (fraction correct) - (fraction incorrect) - OVERHEAD_WEIGHT*(update packets per timestep / (N*(N-1))
     * 
* where N is the number of nodes. */ public double getScore() { if ( numTimestepSamples == 0 ) return 0.0; // the first term, and the -1, is the correct - incorrect part return ((2.0 * sumFractionCorrect) - ConstSysProperties.UPDATE_PACKET_OVERHEAD_WEIGHT * sumFractionUpdates) / numTimestepSamples - 1; } /** * Get average fraction of reachable pairs reachable through routing tables. */ public double getReachableFraction() { return sumFractionReachable / numTimestepSamples; } /** * Get average fration of N*(N-1) pairs that can communicate. */ public double getAvailableFraction() { return (reachableCnt/(double)numTimestepSamples) / numNetworkPairs; } }