commit 6dd30e5beda287cd02fabd257028e1711aa63f99 Author: Damian Johnson atagar@torproject.org Date: Sat Jan 16 19:18:25 2016 -0800
Benchmarks for our descriptor parsing libraries
Karsten, Philipp, and I have been discussing library benchmarks on tor-dev@. Adding the findings...
https://lists.torproject.org/pipermail/tor-dev/2016-January/010230.html --- docs/_static/example/benchmark_metrics_lib.java | 302 ++++++++++++++++++++ .../benchmark_server_descriptor_metrics_lib.java | 49 ++++ .../example/benchmark_server_descriptor_stem.py | 21 ++ .../example/benchmark_server_descriptor_zoossh.go | 68 +++++ docs/_static/example/benchmark_stem.py | 81 ++++++ docs/_static/example/benchmark_zoossh.go | 120 ++++++++ docs/tutorials/mirror_mirror_on_the_wall.rst | 96 +++++-- 7 files changed, 712 insertions(+), 25 deletions(-)
diff --git a/docs/_static/example/benchmark_metrics_lib.java b/docs/_static/example/benchmark_metrics_lib.java new file mode 100644 index 0000000..63b5e4b --- /dev/null +++ b/docs/_static/example/benchmark_metrics_lib.java @@ -0,0 +1,302 @@ +/* Copyright 2016 The Tor Project + * See LICENSE for licensing information */ +package org.torproject.descriptor; + +import java.io.File; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.SortedMap; + +public class MeasurePerformance { + + /* Check if all necessary files are available and then measure + * performance of some more or less common use cases. */ + public static void main(String[] args) { + if (!filesAvailable()) { + return; + } + /*measureListOutdatedRelays(null); + pause();*/ + measureAverageAdvertisedBandwidth(new File(resDir, resPaths[0])); + pause(); + measureAverageAdvertisedBandwidth(new File(resDir, resPaths[1])); + pause(); + measureAverageAdvertisedBandwidth(new File(resDir, resPaths[2])); + pause(); + /*measureFractionRelaysExit80ServerDescriptors(null); + pause(); + measureSumOfWrittenAndReadBytes(null); + pause();*/ + measureCountriesV3Requests(new File(resDir, resPaths[3])); + pause(); + measureCountriesV3Requests(new File(resDir, resPaths[4])); + pause(); + measureAverageRelaysExit(new File(resDir, resPaths[5])); + pause(); + measureAverageRelaysExit(new File(resDir, resPaths[6])); + pause(); + measureAverageRelaysExit(new File(resDir, resPaths[7])); + /*pause(); + measureVotesByBandwidthAuthorities(null); + pause(); + measureExtendedFamilies(null); + pause();*/ + measureFractionRelaysExit80Microdescriptors( + new File(resDir, resPaths[8])); + measureFractionRelaysExit80Microdescriptors( + new File(resDir, resPaths[9])); + } + + private static File resDir = new File("res"); + private static String[] resPaths = new String[] { + "archive/relay-descriptors/server-descriptors/" + + "server-descriptors-2015-11.tar.xz", + "archive/relay-descriptors/server-descriptors/" + + "server-descriptors-2015-11.tar", + "archive/relay-descriptors/server-descriptors/" + + "server-descriptors-2015-11", + "archive/relay-descriptors/extra-infos/extra-infos-2015-11.tar.xz", + "archive/relay-descriptors/extra-infos/extra-infos-2015-11.tar", + "archive/relay-descriptors/consensuses/consensuses-2015-11.tar.xz", + "archive/relay-descriptors/consensuses/consensuses-2015-11.tar", + "archive/relay-descriptors/consensuses/consensuses-2015-11", + "archive/relay-descriptors/microdescs/" + + "microdescs-2015-11-micro.tar.xz", + "archive/relay-descriptors/microdescs/microdescs-2015-11-micro.tar" + }; + + private static boolean filesAvailable() { + if (!resDir.exists() || !resDir.isDirectory()) { + return false; + } + for (String resPath : resPaths) { + if (!(new File(resDir, resPath).exists())) { + System.err.println(resPath); + return false; + } + } + return true; + } + + private static void pause() { + try { + Thread.sleep(15L * 1000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private static void measureListOutdatedRelays(File tarballFile) { + + } + + private static void measureAverageAdvertisedBandwidth( + File tarballFileOrDirectory) { + System.out.println("Starting measureAverageAdvertisedBandwidth"); + long startedMillis = System.currentTimeMillis(); + long sumAdvertisedBandwidth = 0, countedServerDescriptors = 0; + DescriptorReader descriptorReader = + DescriptorSourceFactory.createDescriptorReader(); + descriptorReader.addTarball(tarballFileOrDirectory); + descriptorReader.addDirectory(tarballFileOrDirectory); + Iterator<DescriptorFile> descriptorFiles = + descriptorReader.readDescriptors(); + while (descriptorFiles.hasNext()) { + DescriptorFile descriptorFile = descriptorFiles.next(); + for (Descriptor descriptor : descriptorFile.getDescriptors()) { + if (!(descriptor instanceof ServerDescriptor)) { + continue; + } + ServerDescriptor serverDescriptor = (ServerDescriptor) descriptor; + sumAdvertisedBandwidth += (long) Math.min(Math.min( + serverDescriptor.getBandwidthRate(), + serverDescriptor.getBandwidthBurst()), + serverDescriptor.getBandwidthObserved()); + countedServerDescriptors++; + } + } + long endedMillis = System.currentTimeMillis(); + System.out.println("Ending measureAverageAdvertisedBandwidth"); + System.out.printf("Total time: %d millis%n", + endedMillis - startedMillis); + System.out.printf("Processed server descriptors: %d%n", + countedServerDescriptors); + System.out.printf("Average advertised bandwidth: %d%n", + sumAdvertisedBandwidth / countedServerDescriptors); + System.out.printf("Time per server descriptor: %.6f millis%n", + ((double) (endedMillis - startedMillis)) + / ((double) countedServerDescriptors)); + } + + private static void measureFractionRelaysExit80ServerDescriptors( + File tarballFile) { + + } + + private static void measureSumOfWrittenAndReadBytes(File tarballFile) { + + } + + private static void measureCountriesV3Requests(File tarballFile) { + System.out.println("Starting measureCountriesV3Requests"); + long startedMillis = System.currentTimeMillis(); + Set<String> countries = new HashSet<>(); + long countedExtraInfoDescriptors = 0; + DescriptorReader descriptorReader = + DescriptorSourceFactory.createDescriptorReader(); + descriptorReader.addTarball(tarballFile); + Iterator<DescriptorFile> descriptorFiles = + descriptorReader.readDescriptors(); + while (descriptorFiles.hasNext()) { + DescriptorFile descriptorFile = descriptorFiles.next(); + for (Descriptor descriptor : descriptorFile.getDescriptors()) { + if (!(descriptor instanceof ExtraInfoDescriptor)) { + continue; + } + ExtraInfoDescriptor extraInfoDescriptor = + (ExtraInfoDescriptor) descriptor; + SortedMap<String, Integer> dirreqV3Reqs = + extraInfoDescriptor.getDirreqV3Reqs(); + if (dirreqV3Reqs != null) { + countries.addAll(dirreqV3Reqs.keySet()); + } + countedExtraInfoDescriptors++; + } + } + long endedMillis = System.currentTimeMillis(); + System.out.println("Ending measureCountriesV3Requests"); + System.out.printf("Total time: %d millis%n", + endedMillis - startedMillis); + System.out.printf("Processed extra-info descriptors: %d%n", + countedExtraInfoDescriptors); + System.out.printf("Number of countries: %d%n", + countries.size()); + System.out.printf("Time per extra-info descriptor: %.6f millis%n", + ((double) (endedMillis - startedMillis)) + / ((double) countedExtraInfoDescriptors)); + } + + private static void measureAverageRelaysExit( + File tarballFileOrDirectory) { + System.out.println("Starting measureAverageRelaysExit"); + long startedMillis = System.currentTimeMillis(); + long totalRelaysWithExitFlag = 0L, totalRelays = 0L, + countedConsensuses = 0L; + DescriptorReader descriptorReader = + DescriptorSourceFactory.createDescriptorReader(); + descriptorReader.addTarball(tarballFileOrDirectory); + descriptorReader.addDirectory(tarballFileOrDirectory); + Iterator<DescriptorFile> descriptorFiles = + descriptorReader.readDescriptors(); + while (descriptorFiles.hasNext()) { + DescriptorFile descriptorFile = descriptorFiles.next(); + for (Descriptor descriptor : descriptorFile.getDescriptors()) { + if (!(descriptor instanceof RelayNetworkStatusConsensus)) { + continue; + } + RelayNetworkStatusConsensus consensus = + (RelayNetworkStatusConsensus) descriptor; + for (NetworkStatusEntry entry : + consensus.getStatusEntries().values()) { + if (entry.getFlags().contains("Exit")) { + totalRelaysWithExitFlag++; + } + totalRelays++; + } + countedConsensuses++; + } + } + long endedMillis = System.currentTimeMillis(); + System.out.println("Ending measureAverageRelaysExit"); + System.out.printf("Total time: %d millis%n", + endedMillis - startedMillis); + System.out.printf("Processed consensuses: %d%n", countedConsensuses); + System.out.printf("Total number of status entries: %d%n", + totalRelays); + System.out.printf("Total number of status entries with Exit flag: " + + "%d%n", totalRelaysWithExitFlag); + System.out.printf("Average number of relays with Exit Flag: %.2f%n", + (double) totalRelaysWithExitFlag / (double) totalRelays); + System.out.printf("Time per consensus: %.6f millis%n", + ((double) (endedMillis - startedMillis)) + / ((double) countedConsensuses)); + } + + private static void measureVotesByBandwidthAuthorities( + File tarballFile) { + + } + + private static void measureExtendedFamilies(File tarballFile) { + + } + + private static void measureFractionRelaysExit80Microdescriptors( + File tarballFile) { + System.out.println("Starting " + + "measureFractionRelaysExit80Microdescriptors"); + long startedMillis = System.currentTimeMillis(); + long totalRelaysWithExitFlag = 0L, countedMicrodescriptors = 0L; + DescriptorReader descriptorReader = + DescriptorSourceFactory.createDescriptorReader(); + descriptorReader.addTarball(tarballFile); + Iterator<DescriptorFile> descriptorFiles = + descriptorReader.readDescriptors(); + while (descriptorFiles.hasNext()) { + DescriptorFile descriptorFile = descriptorFiles.next(); + for (Descriptor descriptor : descriptorFile.getDescriptors()) { + if (!(descriptor instanceof Microdescriptor)) { + continue; + } + countedMicrodescriptors++; + Microdescriptor microdescriptor = + (Microdescriptor) descriptor; + String defaultPolicy = microdescriptor.getDefaultPolicy(); + if (defaultPolicy == null) { + continue; + } + boolean accept = "accept".equals( + microdescriptor.getDefaultPolicy()); + for (String ports : microdescriptor.getPortList().split(",")) { + if (ports.contains("-")) { + String[] parts = ports.split("-"); + int from = Integer.parseInt(parts[0]); + int to = Integer.parseInt(parts[1]); + if (from <= 80 && to >= 80) { + if (accept) { + totalRelaysWithExitFlag++; + } + } else if (to > 80) { + if (!accept) { + totalRelaysWithExitFlag++; + } + break; + } + } else if ("80".equals(ports)) { + if (accept) { + totalRelaysWithExitFlag++; + } + break; + } + } + } + } + long endedMillis = System.currentTimeMillis(); + System.out.println("Ending " + + "measureFractionRelaysExit80Microdescriptors"); + System.out.printf("Total time: %d millis%n", + endedMillis - startedMillis); + System.out.printf("Processed microdescriptors: %d%n", + countedMicrodescriptors); + System.out.printf("Total number of microdescriptors that exit to 80: " + + "%d%n", totalRelaysWithExitFlag); + System.out.printf("Average number of relays that exit to 80: %.2f%n", + (double) totalRelaysWithExitFlag + / (double) countedMicrodescriptors); + System.out.printf("Time per microdescriptor: %.6f millis%n", + ((double) (endedMillis - startedMillis)) + / ((double) countedMicrodescriptors)); + } +} + diff --git a/docs/_static/example/benchmark_server_descriptor_metrics_lib.java b/docs/_static/example/benchmark_server_descriptor_metrics_lib.java new file mode 100644 index 0000000..efb8634 --- /dev/null +++ b/docs/_static/example/benchmark_server_descriptor_metrics_lib.java @@ -0,0 +1,49 @@ +package org.torproject.descriptor; + +import java.io.File; +import java.util.Iterator; +import org.torproject.descriptor.DescriptorSourceFactory; + +public class MeasurePerformance { + public static void main(String[] args) { + measureAverageAdvertisedBandwidth(new File("server-descriptors-2015-11.tar")); + } + + private static void measureAverageAdvertisedBandwidth( + File tarballFileOrDirectory) { + System.out.println("Starting measureAverageAdvertisedBandwidth"); + long startedMillis = System.currentTimeMillis(); + long sumAdvertisedBandwidth = 0, countedServerDescriptors = 0; + DescriptorReader descriptorReader = + DescriptorSourceFactory.createDescriptorReader(); + descriptorReader.addTarball(tarballFileOrDirectory); + descriptorReader.addDirectory(tarballFileOrDirectory); + Iterator<DescriptorFile> descriptorFiles = + descriptorReader.readDescriptors(); + while (descriptorFiles.hasNext()) { + DescriptorFile descriptorFile = descriptorFiles.next(); + for (Descriptor descriptor : descriptorFile.getDescriptors()) { + if (!(descriptor instanceof ServerDescriptor)) { + continue; + } + ServerDescriptor serverDescriptor = (ServerDescriptor) descriptor; + sumAdvertisedBandwidth += (long) Math.min(Math.min( + serverDescriptor.getBandwidthRate(), + serverDescriptor.getBandwidthBurst()), + serverDescriptor.getBandwidthObserved()); + countedServerDescriptors++; + } + } + long endedMillis = System.currentTimeMillis(); + System.out.println("Ending measureAverageAdvertisedBandwidth"); + System.out.printf("Total time: %d millis%n", + endedMillis - startedMillis); + System.out.printf("Processed server descriptors: %d%n", + countedServerDescriptors); + System.out.printf("Average advertised bandwidth: %d%n", + sumAdvertisedBandwidth / countedServerDescriptors); + System.out.printf("Time per server descriptor: %.6f millis%n", + ((double) (endedMillis - startedMillis)) + / ((double) countedServerDescriptors)); + } +} diff --git a/docs/_static/example/benchmark_server_descriptor_stem.py b/docs/_static/example/benchmark_server_descriptor_stem.py new file mode 100644 index 0000000..c475652 --- /dev/null +++ b/docs/_static/example/benchmark_server_descriptor_stem.py @@ -0,0 +1,21 @@ +import time +import stem.descriptor + +def measure_average_advertised_bandwidth(path): + start_time = time.time() + total_bw, count = 0, 0 + + for desc in stem.descriptor.parse_file(path): + total_bw += min(desc.average_bandwidth, desc.burst_bandwidth, desc.observed_bandwidth) + count += 1 + + runtime = time.time() - start_time + print("Finished measure_average_advertised_bandwidth('%s')" % path) + print(' Total time: %i seconds' % runtime) + print(' Processed server descriptors: %i' % count) + print(' Average advertised bandwidth: %i' % (total_bw / count)) + print(' Time per server descriptor: %0.5f seconds' % (runtime / count)) + print('') + +if __name__ == '__main__': + measure_average_advertised_bandwidth('server-descriptors-2015-11.tar') diff --git a/docs/_static/example/benchmark_server_descriptor_zoossh.go b/docs/_static/example/benchmark_server_descriptor_zoossh.go new file mode 100644 index 0000000..f72b3fb --- /dev/null +++ b/docs/_static/example/benchmark_server_descriptor_zoossh.go @@ -0,0 +1,68 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "time" + + "git.torproject.org/user/phw/zoossh.git" +) + +var processedDescs int64 = 0 +var totalBw uint64 = 0 + +func Min(a uint64, b uint64, c uint64) uint64 { + min := a + + if b < min { + min = b + } + + if c < min { + min = c + } + + return min +} + +func ProcessDescriptors(path string, info os.FileInfo, err error) error { + if _, err := os.Stat(path); err != nil { + return err + } + + if info.IsDir() { + return nil + } + + consensus, err := zoossh.ParseDescriptorFile(path) + if err != nil { + return err + } + + if (processedDescs % 100) == 0 { + fmt.Printf(".") + } + + for _, getDesc := range consensus.RouterDescriptors { + desc := getDesc() + totalBw += Min(desc.BandwidthAvg, desc.BandwidthBurst, desc.BandwidthObs) + processedDescs++ + } + + return nil +} + +func main() { + before = time.Now() + filepath.Walk("server-descriptors-2015-11", ProcessDescriptors) + fmt.Println() + after = time.Now() + + duration = after.Sub(before) + fmt.Println("Total time for descriptors:", duration) + fmt.Printf("Time per descriptor: %dns\n", + duration.Nanoseconds()/processedDescs) + fmt.Printf("Processed %d descriptors.\n", processedDescs) + fmt.Printf("Average advertised bandwidth: %d\n", totalBw/uint64(processedDescs)) +} diff --git a/docs/_static/example/benchmark_stem.py b/docs/_static/example/benchmark_stem.py new file mode 100644 index 0000000..8b71d73 --- /dev/null +++ b/docs/_static/example/benchmark_stem.py @@ -0,0 +1,81 @@ +import time +import stem.descriptor + +def measure_average_advertised_bandwidth(path): + start_time = time.time() + total_bw, count = 0, 0 + + for desc in stem.descriptor.parse_file(path): + total_bw += min(desc.average_bandwidth, desc.burst_bandwidth, desc.observed_bandwidth) + count += 1 + + runtime = time.time() - start_time + print("Finished measure_average_advertised_bandwidth('%s')" % path) + print(' Total time: %i seconds' % runtime) + print(' Processed server descriptors: %i' % count) + print(' Average advertised bandwidth: %i' % (total_bw / count)) + print(' Time per server descriptor: %0.5f seconds' % (runtime / count)) + print('') + +def measure_countries_v3_requests(path): + start_time = time.time() + countries, count = set(), 0 + + for desc in stem.descriptor.parse_file(path): + if desc.dir_v3_responses: + countries.update(desc.dir_v3_responses.keys()) + + count += 1 + + runtime = time.time() - start_time + print("Finished measure_countries_v3_requests('%s')" % path) + print(' Total time: %i seconds' % runtime) + print(' Processed extrainfo descriptors: %i' % count) + print(' Number of countries: %i' % len(countries)) + print(' Time per extrainfo descriptor: %0.5f seconds' % (runtime / count)) + print('') + +def measure_average_relays_exit(path): + start_time = time.time() + total_relays, exits, consensuses = 0, 0, 0 + + for consensus in stem.descriptor.parse_file(path, document_handler = stem.descriptor.DocumentHandler.DOCUMENT): + for desc in consensus.routers.values(): + if 'Exit' in desc.flags: + exits += 1 + + total_relays += 1 + + consensuses += 1 + + runtime = time.time() - start_time + print("Finished measure_average_relays_exit('%s')" % path) + print(' Total time: %i seconds' % runtime) + print(' Processed %i consensuses with %i router status entries' % (consensuses, total_relays)) + print(' Total exits: %i (%0.2f%%)' % (exits, float(exits) / total_relays)) + print(' Time per consensus: %0.5f seconds' % (runtime / consensuses)) + print('') + +def measure_fraction_relays_exit_80_microdescriptors(path): + start_time = time.time() + exits, count = 0, 0 + + for desc in stem.descriptor.parse_file(path): + if desc.exit_policy.can_exit_to(port = 80): + exits += 1 + + count += 1 + + runtime = time.time() - start_time + print("Finished measure_fraction_relays_exit_80_microdescriptors('%s')" % path) + print(' Total time: %i seconds' % runtime) + print(' Processed microdescriptors: %i' % count) + print(' Total exits to port 80: %i (%0.2f%%)' % (exits, float(exits) / count)) + print(' Time per microdescriptor: %0.5f seconds' % (runtime / count)) + print('') + +measure_average_advertised_bandwidth('/home/atagar/Desktop/server-descriptors-2015-11.tar') +measure_countries_v3_requests('/home/atagar/Desktop/extra-infos-2015-11.tar') +measure_average_relays_exit('/home/atagar/Desktop/consensuses-2015-11.tar') +measure_fraction_relays_exit_80_microdescriptors('/home/atagar/Desktop/microdescs-2015-11.tar') + diff --git a/docs/_static/example/benchmark_zoossh.go b/docs/_static/example/benchmark_zoossh.go new file mode 100644 index 0000000..7cfc04f --- /dev/null +++ b/docs/_static/example/benchmark_zoossh.go @@ -0,0 +1,120 @@ +package main + +import ( + "fmt" + "log" + "os" + "path/filepath" + "time" + + "git.torproject.org/user/phw/zoossh.git" +) + +var processedCons int64 = 0 +var processedDescs int64 = 0 +var totalExits int64 = 0 +var totalRelays int64 = 0 +var totalBw uint64 = 0 + +func Min(a uint64, b uint64, c uint64) uint64 { + + min := a + + if b < min { + min = b + } + + if c < min { + min = c + } + + return min +} + +func ProcessDescriptors(path string, info os.FileInfo, err error) error { + + if _, err := os.Stat(path); err != nil { + return err + } + + if info.IsDir() { + return nil + } + + consensus, err := zoossh.ParseDescriptorFile(path) + if err != nil { + return err + } + + if (processedDescs % 100) == 0 { + fmt.Printf(".") + } + + for _, getDesc := range consensus.RouterDescriptors { + desc := getDesc() + totalBw += Min(desc.BandwidthAvg, desc.BandwidthBurst, desc.BandwidthObs) + processedDescs++ + } + + return nil +} + +func ProcessConsensus(path string, info os.FileInfo, err error) error { + + if _, err := os.Stat(path); err != nil { + return err + } + + if info.IsDir() { + return nil + } + + consensus, err := zoossh.ParseConsensusFile(path) + if err != nil { + return err + } + fmt.Printf(".") + + for _, getStatus := range consensus.RouterStatuses { + status := getStatus() + totalRelays++ + if status.Flags.Exit == true { + totalExits++ + } + } + processedCons++ + + return nil +} + +func main() { + + if len(os.Args) != 3 { + log.Fatalf("Usage: %s CONSENSUS_ARCHIVE DESCRIPTOR_ARCHIVE", os.Args[0]) + } + + before := time.Now() + filepath.Walk(os.Args[1], ProcessConsensus) + fmt.Println() + after := time.Now() + + duration := after.Sub(before) + fmt.Println("Total time for consensuses:", duration) + fmt.Printf("Time per consensus: %dms\n", + duration.Nanoseconds()/processedCons/int64(1000000)) + fmt.Printf("Processed %d consensuses with %d router status entries.\n", + processedCons, totalRelays) + fmt.Printf("Total exits: %d\n", totalExits) + + before = time.Now() + filepath.Walk(os.Args[2], ProcessDescriptors) + fmt.Println() + after = time.Now() + + duration = after.Sub(before) + fmt.Println("Total time for descriptors:", duration) + fmt.Printf("Time per descriptor: %dns\n", + duration.Nanoseconds()/processedDescs) + fmt.Printf("Processed %d descriptors.\n", processedDescs) + fmt.Printf("Average advertised bandwidth: %d\n", totalBw/uint64(processedDescs)) +} diff --git a/docs/tutorials/mirror_mirror_on_the_wall.rst b/docs/tutorials/mirror_mirror_on_the_wall.rst index ee524e4..656d228 100644 --- a/docs/tutorials/mirror_mirror_on_the_wall.rst +++ b/docs/tutorials/mirror_mirror_on_the_wall.rst @@ -263,31 +263,77 @@ Each library has its own capabilities... .. role:: red .. role:: green
-=========================== ================= =============== ============== -Capability Stem Metrics-lib Zoossh -=========================== ================= =============== ============== -Language :green:`Python` :green:`Java` :green:`Go` -Checks signatures :green:`Mostly` :red:`No` :red:`No` -Create new descriptors :red:`No` :red:`No` :red:`No` -Lazy parsing :green:`Yes` :red:`No` :green:`Yes` -Type detection by @type :green:`Yes` :green:`Yes` :green:`Yes` -Type detection by filename :green:`Yes` :red:`No` :red:`No` -Packages :green:`Several` :red:`None` :red:`None` +=========================== ===================== =================== ============== +Capability Stem Metrics-lib Zoossh +=========================== ===================== =================== ============== +Language :green:`Python` :green:`Java` :green:`Go` +Checks signatures :green:`Mostly` :red:`No` :red:`No` +Create new descriptors :red:`No` :red:`No` :red:`No` +Lazy parsing :green:`Yes` :red:`No` :green:`Yes` +Type detection by @type :green:`Yes` :green:`Yes` :green:`Yes` +Type detection by filename :green:`Yes` :red:`No` :red:`No` +Packages :green:`Several` :red:`None` :red:`None` **Can Read/Download From** -Files :green:`Yes` :green:`Yes` :green:`Yes` -Tarballs :green:`Yes` :green:`Yes` :red:`No` -Tor Process :green:`Yes` :red:`No` :red:`No` -Directory Authorities :green:`Yes` :green:`Yes` :red:`No` -CollecTor :red:`No` :green:`Yes` :red:`No` +Files :green:`Yes` :green:`Yes` :green:`Yes` +Tarballs :green:`Yes` :green:`Yes` :red:`No` +Tor Process :green:`Yes` :red:`No` :red:`No` +Directory Authorities :green:`Yes` :green:`Yes` :red:`No` +CollecTor :red:`No` :green:`Yes` :red:`No` **Supported Types** -Server Descriptors :green:`Yes` :green:`Yes` :green:`Partly` -Extrainfo Descriptors :green:`Yes` :green:`Yes` :red:`No` -Microdescriptors :green:`Yes` :green:`Yes` :red:`No` -Consensus :green:`Yes` :green:`Yes` :green:`Partly` -Bridge Descriptors :green:`Yes` :green:`Yes` :red:`No` -Hidden Service Descriptors :green:`Yes` :red:`No` :red:`No` -Bridge Pool Assignments :red:`No` :green:`Yes` :red:`No` -Torperf :red:`No` :green:`Yes` :red:`No` -Tordnsel :green:`Yes` :green:`Yes` :red:`No` -=========================== ================= =============== ============== +Server Descriptors :green:`Yes` :green:`Yes` :green:`Partly` +Extrainfo Descriptors :green:`Yes` :green:`Yes` :red:`No` +Microdescriptors :green:`Yes` :green:`Yes` :red:`No` +Consensus :green:`Yes` :green:`Yes` :green:`Partly` +Bridge Descriptors :green:`Yes` :green:`Yes` :red:`No` +Hidden Service Descriptors :green:`Yes` :red:`No` :red:`No` +Bridge Pool Assignments :red:`No` :green:`Yes` :red:`No` +Torperf :red:`No` :green:`Yes` :red:`No` +Tordnsel :green:`Yes` :green:`Yes` :red:`No` +**Benchmarks** +Server Descriptors :green:`0.63 ms` :green:`0.29 ms` :green:`0.46 ms` +Extrainfo Descriptors :green:`0.42 ms` :green:`0.22 ms` :red:`unsupported` +Microdescriptors :green:`0.34 ms` :green:`0.07 ms` :red:`unsupported` +Consensus :green:`876.09 ms` :green:`246.71 ms` :green:`83.00 ms` +Benchmarked With Commit :green:`c01a9cd` :green:`8767f3e` :green:`2380e55` +Language Interpreter :green:`Python 3.5.1` :green:`Java 1.7.0` :green:`Go 1.5.2` +=========================== ===================== =================== ============== + +Few things to note about these benchmarks... + +* **Zoossh is the fastest.** Its benchmarks were at a disadvantage due to not + reading from tarballs. + +* Your Python version makes a very large difference for Stem. For instance, + with Python 2.7 reading a consensus takes **1,393.10 ms** (almost twice as + long). + +* Metrics-lib and Stem can both read from compressed tarballs at a small + performance cost. For instance, Metrics-lib can read an `lzma compressed + <../faq.html#how-do-i-read-tar-xz-descriptor-archives>`_ consensus in + **255.76 ms** and Stem can do it in **913.12 ms**. + +So what does code with each of these look like? + +Stem Example +------------ + +* `Benchmark Script <../.../../_static/example/benchmark_stem.py>`_ + +.. literalinclude:: /_static/example/benchmark_server_descriptor_stem.py + :language: python + +Metrics-lib Example +------------------- + +* `Benchmark Script <../.../../_static/example/benchmark_metrics_lib.java>`_ + +.. literalinclude:: /_static/example/benchmark_server_descriptor_metrics_lib.java + :language: java + +Zoossh Example +-------------- + +* `Benchmark Script <../.../../_static/example/benchmark_zoossh.go>`_
+.. literalinclude:: /_static/example/benchmark_server_descriptor_zoossh.go + :language: go