commit de7426a511e4ad7d612d248d35766a10e97d7fe5 Author: Karsten Loesing karsten.loesing@gmx.net Date: Wed Jul 25 17:37:34 2012 +0200
Move #5755 code to #6443. --- task-5755/.gitignore | 11 - .../src/CalculatePathSelectionProbabilities.java | 293 -------------------- task-6443/.gitignore | 5 + task-6443/README | 16 +- .../src/CalculatePathSelectionProbabilities.java | 293 ++++++++++++++++++++ 5 files changed, 311 insertions(+), 307 deletions(-)
diff --git a/task-5755/.gitignore b/task-5755/.gitignore deleted file mode 100644 index 5d5ac29..0000000 --- a/task-5755/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -.classpath -.project -*.pdf -bin/ -in/ -lib/ -*.csv -*.png -*.tar -*.tar.bz2 - diff --git a/task-5755/src/CalculatePathSelectionProbabilities.java b/task-5755/src/CalculatePathSelectionProbabilities.java deleted file mode 100644 index 67bb200..0000000 --- a/task-5755/src/CalculatePathSelectionProbabilities.java +++ /dev/null @@ -1,293 +0,0 @@ -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.SortedMap; -import java.util.SortedSet; -import java.util.TimeZone; -import java.util.TreeMap; -import java.util.TreeSet; - -import org.torproject.descriptor.Descriptor; -import org.torproject.descriptor.DescriptorFile; -import org.torproject.descriptor.DescriptorReader; -import org.torproject.descriptor.DescriptorSourceFactory; -import org.torproject.descriptor.NetworkStatusEntry; -import org.torproject.descriptor.RelayNetworkStatusConsensus; -import org.torproject.descriptor.ServerDescriptor; - -/* - * Calculate five path-selection probabilities for relays based on - * consensus weights and advertised bandwidths: - * - * - advertised_bandwidth_fraction: Relative advertised bandwidth of - * this relay compared to the total advertised bandwidth in the - * network. If there were no bandwidth authorities, this fraction - * would be the probability of this relay to be selected by clients. - * - * - consensus_weight_fraction: Fraction of this relay's consensus weight - * compared to the sum of all consensus weights in the network. This - * fraction is a very rough approximation of the probability of this - * relay to be selected by clients. - * - * - guard_probability: Probability of this relay to be selected for the - * guard position. This probability is calculated based on consensus - * weights, relay flags, directory ports, and bandwidth weights in the - * consensus. Path selection depends on more factors, so that this - * probability can only be an approximation. - * - * - middle_probability: Probability of this relay to be selected for the - * middle position. This probability is calculated based on consensus - * weights, relay flags, directory ports, and bandwidth weights in the - * consensus. Path selection depends on more factors, so that this - * probability can only be an approximation. - * - * - exit_probability: Probability of this relay to be selected for the - * exit position. This probability is calculated based on consensus - * weights, relay flags, directory ports, and bandwidth weights in the - * consensus. Path selection depends on more factors, so that this - * probability can only be an approximation. - */ -public class CalculatePathSelectionProbabilities { - public static void main(String[] args) throws Exception { - - /* Note: change to true if raw weights shall be written to disk. */ - boolean writeRawWeights = false; - - /* Read advertised bandwidths of all server descriptors in - * in/server-descriptors/ to memory. This is a rather brute-force - * approach, but it's fine for running this analysis. */ - DescriptorReader descriptorReader = - DescriptorSourceFactory.createDescriptorReader(); - descriptorReader.addDirectory(new File("in/server-descriptors")); - Iterator<DescriptorFile> descriptorFiles = - descriptorReader.readDescriptors(); - Map<String, Integer> serverDescriptors = - new HashMap<String, Integer>(); - while (descriptorFiles.hasNext()) { - DescriptorFile descriptorFile = descriptorFiles.next(); - for (Descriptor descriptor : descriptorFile.getDescriptors()) { - if (!(descriptor instanceof ServerDescriptor)) { - continue; - } - ServerDescriptor serverDescriptor = (ServerDescriptor) descriptor; - String digest = serverDescriptor.getServerDescriptorDigest(); - int advertisedBandwidth = Math.min(Math.min( - serverDescriptor.getBandwidthBurst(), - serverDescriptor.getBandwidthObserved()), - serverDescriptor.getBandwidthRate()); - serverDescriptors.put(digest.toUpperCase(), advertisedBandwidth); - } - } - - /* Go through consensuses in in/consensuses/ in arbitrary order and - * calculate the five path-selection probabilities for each of them. - * Write results for a given consensuses to a single new line per - * relay to out.csv. */ - descriptorReader = DescriptorSourceFactory.createDescriptorReader(); - descriptorReader.addDirectory(new File("in/consensuses")); - descriptorFiles = descriptorReader.readDescriptors(); - BufferedWriter bw = null; - if (writeRawWeights) { - bw = new BufferedWriter(new FileWriter("weights.csv")); - bw.write("validafter,fingerprint,advertised_bandwidth_fraction," - + "consensus_weight_fraction,guard_probability," - + "middle_probability,exit_probability\n"); - } - BufferedWriter bw2 = new BufferedWriter(new FileWriter( - "cumulated-weights.csv")); - bw2.write("validafter,top_relays,total_exit_probability\n"); - BufferedWriter bw3 = new BufferedWriter(new FileWriter( - "inverse-cumulated-weights.csv")); - bw3.write("validafter,total_exit_probability,top_relays\n"); - while (descriptorFiles.hasNext()) { - DescriptorFile descriptorFile = descriptorFiles.next(); - for (Descriptor descriptor : descriptorFile.getDescriptors()) { - if (!(descriptor instanceof RelayNetworkStatusConsensus)) { - continue; - } - RelayNetworkStatusConsensus consensus = - (RelayNetworkStatusConsensus) descriptor; - - /* Extract valid-after time and bandwidth weights from the parsed - * consensus. */ - SimpleDateFormat dateTimeFormat = new SimpleDateFormat( - "yyyy-MM-dd HH:mm:ss"); - dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - String validAfter = dateTimeFormat.format( - consensus.getValidAfterMillis()); - SortedMap<String, Integer> bandwidthWeights = - consensus.getBandwidthWeights(); - if (bandwidthWeights == null) { - /* Consensus doesn't contain any bandwidth weights. */ - continue; - } - SortedSet<String> weightKeys = new TreeSet<String>(Arrays.asList(( - "Wgg,Wgm,Wgd,Wmg,Wmm,Wme,Wmd,Weg,Wem,Wee,Wed,Wgb,Wmb,Web,Wdb," - + "Wbg,Wbm,Wbe,Wbd").split(","))); - weightKeys.removeAll(bandwidthWeights.keySet()); - if (!weightKeys.isEmpty()) { - /* Consensus is missing at least some required bandwidth - * weights. */ - continue; - } - double wgg = ((double) bandwidthWeights.get("Wgg")) / 10000.0, - wgd = ((double) bandwidthWeights.get("Wgd")) / 10000.0, - wmg = ((double) bandwidthWeights.get("Wmg")) / 10000.0, - wmm = ((double) bandwidthWeights.get("Wmm")) / 10000.0, - wme = ((double) bandwidthWeights.get("Wme")) / 10000.0, - wmd = ((double) bandwidthWeights.get("Wmd")) / 10000.0, - wee = ((double) bandwidthWeights.get("Wee")) / 10000.0, - wed = ((double) bandwidthWeights.get("Wed")) / 10000.0; - - /* Go through network statuses and calculate the five weights for - * each of them. Also sum up totals to calculate probabilities - * later. */ - SortedMap<String, Double> - advertisedBandwidths = new TreeMap<String, Double>(), - consensusWeights = new TreeMap<String, Double>(), - guardWeights = new TreeMap<String, Double>(), - middleWeights = new TreeMap<String, Double>(), - exitWeights = new TreeMap<String, Double>(); - double totalAdvertisedBandwidth = 0.0; - double totalConsensusWeight = 0.0; - double totalGuardWeight = 0.0; - double totalMiddleWeight = 0.0; - double totalExitWeight = 0.0; - for (NetworkStatusEntry relay : - consensus.getStatusEntries().values()) { - String fingerprint = relay.getFingerprint(); - if (!relay.getFlags().contains("Running")) { - continue; - } - boolean isExit = relay.getFlags().contains("Exit") && - !relay.getFlags().contains("BadExit"); - boolean isGuard = relay.getFlags().contains("Guard"); - String serverDescriptorDigest = relay.getDescriptor(). - toUpperCase(); - double advertisedBandwidth; - if (!serverDescriptors.containsKey(serverDescriptorDigest)) { - advertisedBandwidth = 0.0; - } else { - advertisedBandwidth = (double) serverDescriptors.get( - serverDescriptorDigest); - } - double consensusWeight = (double) relay.getBandwidth(); - double guardWeight = (double) relay.getBandwidth(); - double middleWeight = (double) relay.getBandwidth(); - double exitWeight = (double) relay.getBandwidth(); - - /* Case 1: relay has both Guard and Exit flag and could be - * selected for either guard, middle, or exit position. Apply - * bandwidth weights W?d. */ - if (isGuard && isExit) { - guardWeight *= wgd; - middleWeight *= wmd; - exitWeight *= wed; - - /* Case 2: relay only has the Guard flag, not the Exit flag. - * While, in theory, the relay could also be picked for the exit - * position (if it has a weird exit policy), Weg is hard-coded - * to 0 here. Otherwise, relays with exit policy reject *:* - * would show up as possible exits, which makes no sense. Maybe - * this is too much of an oversimplification? For the other - * positions, apply bandwidth weights W?g. */ - } else if (isGuard) { - guardWeight *= wgg; - middleWeight *= wmg; - exitWeight = 0.0; - - /* Case 3: relay only has the Exit flag, not the Guard flag. It - * cannot be picked for the guard position, so set Wge to 0. - * For the other positions, apply bandwidth weights W?e. */ - } else if (isExit) { - guardWeight = 0.0; - middleWeight *= wme; - exitWeight *= wee; - - /* Case 4: relay has neither Exit nor Guard flag. Similar to - * case 2, this relay *could* have a weird exit policy and be - * picked in the exit position. Same rationale applies, so Wme - * is set to 0. The relay cannot be a guard, so Wgm is 0, too. - * For middle position, apply bandwidth weight Wmm. */ - } else { - guardWeight = 0.0; - middleWeight *= wmm; - exitWeight = 0.0; - } - - /* Store calculated weights and update totals. */ - advertisedBandwidths.put(fingerprint, advertisedBandwidth); - consensusWeights.put(fingerprint, consensusWeight); - guardWeights.put(fingerprint, guardWeight); - middleWeights.put(fingerprint, middleWeight); - exitWeights.put(fingerprint, exitWeight); - totalAdvertisedBandwidth += advertisedBandwidth; - totalConsensusWeight += consensusWeight; - totalGuardWeight += guardWeight; - totalMiddleWeight += middleWeight; - totalExitWeight += exitWeight; - } - - /* Write calculated path-selection probabilities to the output - * file. */ - if (bw != null) { - for (NetworkStatusEntry relay : - consensus.getStatusEntries().values()) { - String fingerprint = relay.getFingerprint(); - bw.write(String.format("%s,%s,%.9f,%.9f,%.9f,%.9f,%.9f%n", - validAfter, - fingerprint, - advertisedBandwidths.get(fingerprint) - / totalAdvertisedBandwidth, - consensusWeights.get(fingerprint) / totalConsensusWeight, - guardWeights.get(fingerprint) / totalGuardWeight, - middleWeights.get(fingerprint) / totalMiddleWeight, - exitWeights.get(fingerprint) / totalExitWeight)); - } - } - - /* Write exit probabilities for top-x relays to the second and - * third output files. */ - List<Double> sortedExitWeights = new ArrayList<Double>( - exitWeights.values()); - Collections.sort(sortedExitWeights); - Collections.reverse(sortedExitWeights); - int topRelays = 0; - double totalExitProbability = 0.0; - List<Double> inverseProbabilities = new ArrayList<Double>( - Arrays.asList(new Double[] { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, - 0.7, 0.8, 0.9 })); - for (double exitWeight : sortedExitWeights) { - topRelays++; - totalExitProbability += exitWeight / totalExitWeight; - if (topRelays <= 50) { - bw2.write(String.format("%s,%d,%.9f%n", validAfter, topRelays, - totalExitProbability)); - } - while (!inverseProbabilities.isEmpty() && - totalExitProbability > inverseProbabilities.get(0)) { - bw3.write(String.format("%s,%.1f,%d%n", validAfter, - inverseProbabilities.remove(0), topRelays)); - } - if (inverseProbabilities.isEmpty() && topRelays > 50) { - break; - } - } - } - } - if (bw != null) { - bw.close(); - } - bw2.close(); - bw3.close(); - } -} - diff --git a/task-6443/.gitignore b/task-6443/.gitignore index 6a3a120..97fd265 100644 --- a/task-6443/.gitignore +++ b/task-6443/.gitignore @@ -1,3 +1,8 @@ +.classpath +.project +bin/ +in/ +lib/ *.csv *.pdf *.png diff --git a/task-6443/README b/task-6443/README index 5f10bdf..57ff483 100644 --- a/task-6443/README +++ b/task-6443/README @@ -1,7 +1,17 @@ Graph cdf of probability of selecting among the biggest k exits (#6443)
-- Run #5755 code to produce cumulated-weights.csv and - inverse-cumulated-weights.csv and copy those files to this directory. +- Put consensuses and server descriptors into newly created directories + in/consensuses/ and in/server-descriptors/.
-- Plot CDFs using: R --slave -f cumulated-weights.R +- Put metrics-lib's descriptor.jar, commons-codec, and commons-compress + into lib/ directory. + +- Compile Java class: + $ javac -d bin -cp lib/descriptor.jar src/CalculatePathSelectionProbabilities.java + +- Run Java class: + $ java -cp bin:lib/descriptor.jar:lib/commons-codec-1.6.jar:lib/commons-compress-1.4.1.jar CalculatePathSelectionProbabilities + +- Plot graphs: + $ R --slave -f cumulated-weights.R
diff --git a/task-6443/src/CalculatePathSelectionProbabilities.java b/task-6443/src/CalculatePathSelectionProbabilities.java new file mode 100644 index 0000000..67bb200 --- /dev/null +++ b/task-6443/src/CalculatePathSelectionProbabilities.java @@ -0,0 +1,293 @@ +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TimeZone; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.torproject.descriptor.Descriptor; +import org.torproject.descriptor.DescriptorFile; +import org.torproject.descriptor.DescriptorReader; +import org.torproject.descriptor.DescriptorSourceFactory; +import org.torproject.descriptor.NetworkStatusEntry; +import org.torproject.descriptor.RelayNetworkStatusConsensus; +import org.torproject.descriptor.ServerDescriptor; + +/* + * Calculate five path-selection probabilities for relays based on + * consensus weights and advertised bandwidths: + * + * - advertised_bandwidth_fraction: Relative advertised bandwidth of + * this relay compared to the total advertised bandwidth in the + * network. If there were no bandwidth authorities, this fraction + * would be the probability of this relay to be selected by clients. + * + * - consensus_weight_fraction: Fraction of this relay's consensus weight + * compared to the sum of all consensus weights in the network. This + * fraction is a very rough approximation of the probability of this + * relay to be selected by clients. + * + * - guard_probability: Probability of this relay to be selected for the + * guard position. This probability is calculated based on consensus + * weights, relay flags, directory ports, and bandwidth weights in the + * consensus. Path selection depends on more factors, so that this + * probability can only be an approximation. + * + * - middle_probability: Probability of this relay to be selected for the + * middle position. This probability is calculated based on consensus + * weights, relay flags, directory ports, and bandwidth weights in the + * consensus. Path selection depends on more factors, so that this + * probability can only be an approximation. + * + * - exit_probability: Probability of this relay to be selected for the + * exit position. This probability is calculated based on consensus + * weights, relay flags, directory ports, and bandwidth weights in the + * consensus. Path selection depends on more factors, so that this + * probability can only be an approximation. + */ +public class CalculatePathSelectionProbabilities { + public static void main(String[] args) throws Exception { + + /* Note: change to true if raw weights shall be written to disk. */ + boolean writeRawWeights = false; + + /* Read advertised bandwidths of all server descriptors in + * in/server-descriptors/ to memory. This is a rather brute-force + * approach, but it's fine for running this analysis. */ + DescriptorReader descriptorReader = + DescriptorSourceFactory.createDescriptorReader(); + descriptorReader.addDirectory(new File("in/server-descriptors")); + Iterator<DescriptorFile> descriptorFiles = + descriptorReader.readDescriptors(); + Map<String, Integer> serverDescriptors = + new HashMap<String, Integer>(); + while (descriptorFiles.hasNext()) { + DescriptorFile descriptorFile = descriptorFiles.next(); + for (Descriptor descriptor : descriptorFile.getDescriptors()) { + if (!(descriptor instanceof ServerDescriptor)) { + continue; + } + ServerDescriptor serverDescriptor = (ServerDescriptor) descriptor; + String digest = serverDescriptor.getServerDescriptorDigest(); + int advertisedBandwidth = Math.min(Math.min( + serverDescriptor.getBandwidthBurst(), + serverDescriptor.getBandwidthObserved()), + serverDescriptor.getBandwidthRate()); + serverDescriptors.put(digest.toUpperCase(), advertisedBandwidth); + } + } + + /* Go through consensuses in in/consensuses/ in arbitrary order and + * calculate the five path-selection probabilities for each of them. + * Write results for a given consensuses to a single new line per + * relay to out.csv. */ + descriptorReader = DescriptorSourceFactory.createDescriptorReader(); + descriptorReader.addDirectory(new File("in/consensuses")); + descriptorFiles = descriptorReader.readDescriptors(); + BufferedWriter bw = null; + if (writeRawWeights) { + bw = new BufferedWriter(new FileWriter("weights.csv")); + bw.write("validafter,fingerprint,advertised_bandwidth_fraction," + + "consensus_weight_fraction,guard_probability," + + "middle_probability,exit_probability\n"); + } + BufferedWriter bw2 = new BufferedWriter(new FileWriter( + "cumulated-weights.csv")); + bw2.write("validafter,top_relays,total_exit_probability\n"); + BufferedWriter bw3 = new BufferedWriter(new FileWriter( + "inverse-cumulated-weights.csv")); + bw3.write("validafter,total_exit_probability,top_relays\n"); + while (descriptorFiles.hasNext()) { + DescriptorFile descriptorFile = descriptorFiles.next(); + for (Descriptor descriptor : descriptorFile.getDescriptors()) { + if (!(descriptor instanceof RelayNetworkStatusConsensus)) { + continue; + } + RelayNetworkStatusConsensus consensus = + (RelayNetworkStatusConsensus) descriptor; + + /* Extract valid-after time and bandwidth weights from the parsed + * consensus. */ + SimpleDateFormat dateTimeFormat = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss"); + dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + String validAfter = dateTimeFormat.format( + consensus.getValidAfterMillis()); + SortedMap<String, Integer> bandwidthWeights = + consensus.getBandwidthWeights(); + if (bandwidthWeights == null) { + /* Consensus doesn't contain any bandwidth weights. */ + continue; + } + SortedSet<String> weightKeys = new TreeSet<String>(Arrays.asList(( + "Wgg,Wgm,Wgd,Wmg,Wmm,Wme,Wmd,Weg,Wem,Wee,Wed,Wgb,Wmb,Web,Wdb," + + "Wbg,Wbm,Wbe,Wbd").split(","))); + weightKeys.removeAll(bandwidthWeights.keySet()); + if (!weightKeys.isEmpty()) { + /* Consensus is missing at least some required bandwidth + * weights. */ + continue; + } + double wgg = ((double) bandwidthWeights.get("Wgg")) / 10000.0, + wgd = ((double) bandwidthWeights.get("Wgd")) / 10000.0, + wmg = ((double) bandwidthWeights.get("Wmg")) / 10000.0, + wmm = ((double) bandwidthWeights.get("Wmm")) / 10000.0, + wme = ((double) bandwidthWeights.get("Wme")) / 10000.0, + wmd = ((double) bandwidthWeights.get("Wmd")) / 10000.0, + wee = ((double) bandwidthWeights.get("Wee")) / 10000.0, + wed = ((double) bandwidthWeights.get("Wed")) / 10000.0; + + /* Go through network statuses and calculate the five weights for + * each of them. Also sum up totals to calculate probabilities + * later. */ + SortedMap<String, Double> + advertisedBandwidths = new TreeMap<String, Double>(), + consensusWeights = new TreeMap<String, Double>(), + guardWeights = new TreeMap<String, Double>(), + middleWeights = new TreeMap<String, Double>(), + exitWeights = new TreeMap<String, Double>(); + double totalAdvertisedBandwidth = 0.0; + double totalConsensusWeight = 0.0; + double totalGuardWeight = 0.0; + double totalMiddleWeight = 0.0; + double totalExitWeight = 0.0; + for (NetworkStatusEntry relay : + consensus.getStatusEntries().values()) { + String fingerprint = relay.getFingerprint(); + if (!relay.getFlags().contains("Running")) { + continue; + } + boolean isExit = relay.getFlags().contains("Exit") && + !relay.getFlags().contains("BadExit"); + boolean isGuard = relay.getFlags().contains("Guard"); + String serverDescriptorDigest = relay.getDescriptor(). + toUpperCase(); + double advertisedBandwidth; + if (!serverDescriptors.containsKey(serverDescriptorDigest)) { + advertisedBandwidth = 0.0; + } else { + advertisedBandwidth = (double) serverDescriptors.get( + serverDescriptorDigest); + } + double consensusWeight = (double) relay.getBandwidth(); + double guardWeight = (double) relay.getBandwidth(); + double middleWeight = (double) relay.getBandwidth(); + double exitWeight = (double) relay.getBandwidth(); + + /* Case 1: relay has both Guard and Exit flag and could be + * selected for either guard, middle, or exit position. Apply + * bandwidth weights W?d. */ + if (isGuard && isExit) { + guardWeight *= wgd; + middleWeight *= wmd; + exitWeight *= wed; + + /* Case 2: relay only has the Guard flag, not the Exit flag. + * While, in theory, the relay could also be picked for the exit + * position (if it has a weird exit policy), Weg is hard-coded + * to 0 here. Otherwise, relays with exit policy reject *:* + * would show up as possible exits, which makes no sense. Maybe + * this is too much of an oversimplification? For the other + * positions, apply bandwidth weights W?g. */ + } else if (isGuard) { + guardWeight *= wgg; + middleWeight *= wmg; + exitWeight = 0.0; + + /* Case 3: relay only has the Exit flag, not the Guard flag. It + * cannot be picked for the guard position, so set Wge to 0. + * For the other positions, apply bandwidth weights W?e. */ + } else if (isExit) { + guardWeight = 0.0; + middleWeight *= wme; + exitWeight *= wee; + + /* Case 4: relay has neither Exit nor Guard flag. Similar to + * case 2, this relay *could* have a weird exit policy and be + * picked in the exit position. Same rationale applies, so Wme + * is set to 0. The relay cannot be a guard, so Wgm is 0, too. + * For middle position, apply bandwidth weight Wmm. */ + } else { + guardWeight = 0.0; + middleWeight *= wmm; + exitWeight = 0.0; + } + + /* Store calculated weights and update totals. */ + advertisedBandwidths.put(fingerprint, advertisedBandwidth); + consensusWeights.put(fingerprint, consensusWeight); + guardWeights.put(fingerprint, guardWeight); + middleWeights.put(fingerprint, middleWeight); + exitWeights.put(fingerprint, exitWeight); + totalAdvertisedBandwidth += advertisedBandwidth; + totalConsensusWeight += consensusWeight; + totalGuardWeight += guardWeight; + totalMiddleWeight += middleWeight; + totalExitWeight += exitWeight; + } + + /* Write calculated path-selection probabilities to the output + * file. */ + if (bw != null) { + for (NetworkStatusEntry relay : + consensus.getStatusEntries().values()) { + String fingerprint = relay.getFingerprint(); + bw.write(String.format("%s,%s,%.9f,%.9f,%.9f,%.9f,%.9f%n", + validAfter, + fingerprint, + advertisedBandwidths.get(fingerprint) + / totalAdvertisedBandwidth, + consensusWeights.get(fingerprint) / totalConsensusWeight, + guardWeights.get(fingerprint) / totalGuardWeight, + middleWeights.get(fingerprint) / totalMiddleWeight, + exitWeights.get(fingerprint) / totalExitWeight)); + } + } + + /* Write exit probabilities for top-x relays to the second and + * third output files. */ + List<Double> sortedExitWeights = new ArrayList<Double>( + exitWeights.values()); + Collections.sort(sortedExitWeights); + Collections.reverse(sortedExitWeights); + int topRelays = 0; + double totalExitProbability = 0.0; + List<Double> inverseProbabilities = new ArrayList<Double>( + Arrays.asList(new Double[] { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.7, 0.8, 0.9 })); + for (double exitWeight : sortedExitWeights) { + topRelays++; + totalExitProbability += exitWeight / totalExitWeight; + if (topRelays <= 50) { + bw2.write(String.format("%s,%d,%.9f%n", validAfter, topRelays, + totalExitProbability)); + } + while (!inverseProbabilities.isEmpty() && + totalExitProbability > inverseProbabilities.get(0)) { + bw3.write(String.format("%s,%.1f,%d%n", validAfter, + inverseProbabilities.remove(0), topRelays)); + } + if (inverseProbabilities.isEmpty() && topRelays > 50) { + break; + } + } + } + } + if (bw != null) { + bw.close(); + } + bw2.close(); + bw3.close(); + } +} +