commit 33984e92c72c799751845b8279822ab513a9df52 Author: Zack Weinberg zackw@panix.com Date: Tue Feb 28 08:37:12 2012 -0800
Version of scripts actually used for paper. --- scripts/benchmark-plot.R | 63 +++++++++++- scripts/benchmark.py | 233 +++++++++++++++++++++++++----------------- scripts/bm-tor-controller.py | 118 ++++++++++++---------- 3 files changed, 263 insertions(+), 151 deletions(-)
diff --git a/scripts/benchmark-plot.R b/scripts/benchmark-plot.R index a58ae0a..1ae178d 100644 --- a/scripts/benchmark-plot.R +++ b/scripts/benchmark-plot.R @@ -1,7 +1,68 @@ #! /usr/bin/Rscript
suppressPackageStartupMessages({ + library(plyr) library(ggplot2) + library(tikzDevice) })
-lf.direct <- read.csv("bench-lf-direct.tab", header=TRUE) +peval.raw <- read.csv("perf-eval.csv", header=TRUE) + +peval.u <- rename(ddply(peval.raw, .(benchmark,relay,cap), + function(x) fivenum(x$up)), + c(V1='min', V2='lhinge', V3='med', V4='uhinge', V5='max')) +peval.d <- rename(ddply(peval.raw, .(benchmark,relay,cap), + function(x) fivenum(x$down)), + c(V1='min', V2='lhinge', V3='med', V4='uhinge', V5='max')) + +# pareto became unstable at 50 connections per second +peval.u <- subset(peval.u, benchmark!='files.pareto'|cap<=50) +peval.d <- subset(peval.d, benchmark!='files.pareto'|cap<=50) + +peval.u$direction <- factor("KBps upstream") +peval.d$direction <- factor("KBps downstream") + +peval <- rbind(peval.u, peval.d) + +# force x=0 to appear on all the subplots +zeroes <- ddply(peval, .(benchmark, relay, direction), + function(x) data.frame(cap=0,min=0,lhinge=0,med=0, + uhinge=0,max=0)) +peval <- rbind(peval, zeroes) + +peval$benchmark <- ordered(peval$benchmark, + levels=c("fixedrate", "files.fixed", "files.pareto"), + labels=c("Fixed rate stream", "Fixed-size files", + "Pareto-distributed files")) + +peval$Relay <- ordered(peval$relay, + levels=c("direct", "tor", "st.http"), + labels=c("Direct", "Tor", "StegoTorus (HTTP)")) + +RelayFill=c("Direct"="#666666", "Tor"="#72B8E7", + "StegoTorus (HTTP)"="#E31A1C") + +RelayColors=c("Direct"="#666666", "Tor"="#1F78B4", + "StegoTorus (HTTP)"="#E31A1C") + +graf <- ggplot(peval, aes(x=cap, ymin=lhinge, ymax=uhinge, y=med)) + + geom_ribbon(aes(fill=Relay), alpha=0.3) + + geom_line(aes(colour=Relay)) + + facet_grid(direction~benchmark, scales='free') + + scale_x_continuous(expand=c(.01,0)) + + scale_y_continuous(expand=c(0,0)) + + scale_colour_manual(values=RelayColors) + + scale_fill_manual(values=RelayFill) + + theme_bw(base_size=8) + + opts(panel.border=theme_blank(), + legend.key=theme_blank(), + legend.title=theme_blank(), + legend.background=theme_rect(fill="white",colour=NA), + legend.position=c(0.1,0.8), + strip.background=theme_blank(), + axis.ticks.margin=unit(0.25, "lines") + ) + +tikz(file="perf-eval.tex", width=6.5, height=3, standAlone=TRUE) +print(graf) +invisible(dev.off()) diff --git a/scripts/benchmark.py b/scripts/benchmark.py index be45467..8029f11 100755 --- a/scripts/benchmark.py +++ b/scripts/benchmark.py @@ -27,8 +27,8 @@ # # nylon: http://monkey.org/~marius/pages/?page=nylon # tor, stegotorus -# -# You configure this script by setting variables below. + +# CONFIGURATION - ADJUST VARIABLES BELOW AS NECESSARY
# Client host
@@ -39,18 +39,13 @@ CLIENT_IFACE = "eth0"
PROXY = "sandbox03.sv.cmu.edu" PROXY_IP = "209.129.244.30" # some things won't do DNS for this -PROXY_PORT = "1080" +PROXY_PORT = 1080 PROXY_SSH_CMD = ("ssh", PROXY)
# Target
TARGET = "storustest.nfshost.com"
-# For some reason, bm-fixedrate generates data a linear factor slower -# than it was meant to; this is the quick fix. - -FUDGE_FIXEDRATE = 1.939 - # Programs we need to run. Change these if any binary is not in the # default path or hasn't got the default name. # C_ - for the client. P_ - for the proxy. @@ -59,15 +54,23 @@ FUDGE_FIXEDRATE = 1.939
C_bwm = "bwm-ng" C_mcurl = "bm-mcurl" -C_storus = "stegotorus-wrapper" +C_storus = "stegotorus" C_tor = "/usr/sbin/tor"
P_nylon = "nylon" -P_storus = "stegotorus-wrapper" +P_storus = "./stegotorus/build/stegotorus" P_tor = "tor" P_python = "/usr/local/bin/python" # this must be an absolute path, # it goes on a shebang line
+# For some reason, bm-fixedrate generates data a linear factor slower +# than it was meant to; this is the quick fix. To calibrate this +# number, set it to 1 and run the direct fixedrate test, do a linear +# regression on 'down' as a function of 'cap', and the number you want +# is 1 over the slope of the line. + +FUDGE_FIXEDRATE = 1.939 + # ACTUAL PROGRAM STARTS HERE
from types import MethodType @@ -220,28 +223,38 @@ Verbose=0 PIDfile=nylon.pid
[Server] -Port=%s +Port=%d Allow-IP=%s/32 """ % (PROXY_PORT, CLIENT_IP))
-def p_tor_direct(): - return ProxyProcess((P_tor, "--quiet", "-f", "tor-direct.conf"), - "tor-direct.conf", +def p_tor(): + return ProxyProcess((P_tor, "--quiet", "-f", "tor.conf"), + "tor.conf", """\ -ORPort %s +ORPort %d SocksPort 0 BridgeRelay 1 AssumeReachable 1 PublishServerDescriptor 0 -ExitPolicy reject *:* +ExitPolicy accept *:80 DataDirectory . Log err stderr ContactInfo zackw at cmu dot edu Nickname storustest +AllowSingleHopExits 1 # unfortunately there doesn't seem to be any way to tell Tor to accept # OR connections from specific IP addresses only. """ % PROXY_PORT)
+def p_storus(smode): + return ProxyProcess((P_storus, "--log-min-severity=warn", + "chop", "server", "127.0.0.1:%d" % PROXY_PORT, + "%s:%d" % (PROXY_IP, PROXY_PORT+1), smode, + "%s:%d" % (PROXY_IP, PROXY_PORT+2), smode, + "%s:%d" % (PROXY_IP, PROXY_PORT+3), smode, + "%s:%d" % (PROXY_IP, PROXY_PORT+4), smode)) + + class ClientProcess(subprocess.Popen): """A process running on the local machine. This is probably doing the meat of the work of some benchmark. Basically a shim around @@ -264,80 +277,91 @@ def c_tor_direct(): fp = open("tor-direct-client.conf", "w") fp.write("""\ ORPort 0 -SocksPort %s +SocksPort %d DataDirectory . Log err stderr -Bridge %s:%s +Bridge %s:%d UseBridges 1 SafeSocks 0 ControlPort 9051 +AllowSingleHopCircuits 1 +ExcludeSingleHopRelays 0 __DisablePredictedCircuits 1 __LeaveStreamsUnattached 1 """ % (PROXY_PORT, PROXY_IP, PROXY_PORT)) fp.close() return ClientProcess((C_tor, "--quiet", "-f", "tor-direct-client.conf"))
+def c_tor_storus(): + fp = open("tor-storus-client.conf", "w") + fp.write("""\ +ORPort 0 +SocksPort %d +Socks5Proxy 127.0.0.1:%s +DataDirectory . +Log err stderr +Bridge %s:%d +UseBridges 1 +SafeSocks 0 +ControlPort 9051 +AllowSingleHopCircuits 1 +ExcludeSingleHopRelays 0 +__DisablePredictedCircuits 1 +__LeaveStreamsUnattached 1 +""" % (PROXY_PORT, PROXY_PORT+1, PROXY_IP, PROXY_PORT)) + fp.close() + return ClientProcess((C_tor, "--quiet", "-f", "tor-storus-client.conf")) + +def c_storus(smode): + return ClientProcess((C_storus, "--log-min-severity=warn", + "chop", "socks", "127.0.0.1:%d" % (PROXY_PORT+1), + "%s:%d" % (PROXY_IP, PROXY_PORT+1), smode, + "%s:%d" % (PROXY_IP, PROXY_PORT+2), smode, + "%s:%d" % (PROXY_IP, PROXY_PORT+3), smode, + "%s:%d" % (PROXY_IP, PROXY_PORT+4), smode)) + def c_torctl(): - return ClientProcess((os.path.dirname(__file__) + '/bm-tor-controller.py')) + return ClientProcess((os.path.dirname(__file__) + '/bm-tor-controller.py' + ))
def c_curl(url, proxyhost): return ClientProcess((C_mcurl, '1', '1', - proxyhost + ":" + PROXY_PORT, + proxyhost + ":" + str(PROXY_PORT), url))
def c_mcurl(prefix, cps, proxyhost): return ClientProcess((C_mcurl, str(cps), '200', - proxyhost + ':' + PROXY_PORT, + proxyhost + ':' + str(PROXY_PORT), 'http://' + TARGET + '/' + prefix + '/[0-9]/[0-9]/[0-9]/[0-9].html'))
# Benchmarks.
-def bench_fixedrate_direct(report): - client = None +def t_direct(report, bench, *args): proxy = None try: proxy = p_nylon()
- for cap in range(10,810,10): - sys.stderr.write("fixedrate,direct,%d\n" % (cap * 1000)) - try: - client = c_curl('http://' + TARGET + '/bm-fixedrate.cgi/' + - str(int(cap * 1000 * FUDGE_FIXEDRATE)), - PROXY) - monitor(report, "fixedrate,direct,%d" % cap, 10) - finally: - if client is not None: - client.terminate() - client.wait() - client = None + bench(report, PROXY_IP, "direct", *args) + finally: if proxy is not None: proxy.terminate() proxy.wait()
-def bench_fixedrate_tor(report): - client = None +def t_tor(report, bench, *args): proxy = None proxyl = None + proxyc = None try: - proxy = p_tor_direct() + proxy = p_tor() proxyl = c_tor_direct() + time.sleep(1) proxyc = c_torctl() - time.sleep(5) # tor startup is slow - - for cap in range(10,810,10): - sys.stderr.write("fixedrate,tor,%d\n" % cap) - try: - client = c_curl('http://' + TARGET + '/bm-fixedrate.cgi/' + - str(int(cap * 1000 * FUDGE_FIXEDRATE)), - '127.0.0.1') - monitor(report, "fixedrate,tor,%d" % cap, 60) - finally: - if client is not None: - client.terminate() - client.wait() - client = None + time.sleep(4) + + bench(report, '127.0.0.1', "tor", *args) + finally: if proxy is not None: proxy.terminate() @@ -349,47 +373,23 @@ def bench_fixedrate_tor(report): proxyl.terminate() proxyl.wait()
-def bench_files_direct(report, prefix, maxconn): - client = None - proxy = None - try: - proxy = p_nylon() - - for cps in range(1,maxconn+1): - sys.stderr.write("files.%s,direct,%d\n" % (prefix, cps)) - try: - client = c_mcurl(prefix, cps, PROXY_IP) - monitor(report, "files.%s,direct,%d" % (prefix, cps), 60) - finally: - if client is not None: - client.terminate() - client.wait() - client = None - finally: - if proxy is not None: - proxy.terminate() - proxy.wait() - -def bench_files_tor(report, prefix, maxconn): - client = None +def t_storus(report, bench, smode, *args): proxy = None + proxys = None proxyl = None + proxym = None + proxyc = None try: - proxy = p_tor_direct() - proxyl = c_tor_direct() + proxy = p_tor() + proxys = p_storus(smode) + proxyl = c_tor_storus() + proxym = c_storus(smode) + time.sleep(1) proxyc = c_torctl() - time.sleep(5) # tor startup is slow - - for cps in range(1,maxconn+1): - sys.stderr.write("files.%s,tor,%d\n" % (prefix, cps)) - try: - client = c_mcurl(prefix, cps, '127.0.0.1') - monitor(report, "files.%s,tor,%d" % (prefix, cps), 60) - finally: - if client is not None: - client.terminate() - client.wait() - client = None + time.sleep(4) + + bench(report, '127.0.0.1', "st.http", *args) + finally: if proxy is not None: proxy.terminate() @@ -400,12 +400,53 @@ def bench_files_tor(report, prefix, maxconn): if proxyl is not None: proxyl.terminate() proxyl.wait() + if proxys is not None: + proxys.terminate() + proxys.wait() + if proxym is not None: + proxym.terminate() + proxym.wait() + +def bench_fixedrate(report, proxyaddr, relay, bmax, bstep, mtime): + for cap in range(bstep, bmax+bstep, bstep): + tag = "fixedrate,%s,%d" % (relay, cap) + sys.stderr.write(tag + "\n") + try: + client = c_curl('http://' + TARGET + '/bm-fixedrate.cgi/' + + str(int(cap * 1000 * FUDGE_FIXEDRATE)), + proxyaddr) + monitor(report, tag, mtime) + finally: + if client is not None: + client.terminate() + client.wait() + client = None + +def bench_files(report, proxyaddr, relay, prefix, maxconn, mtime): + for cps in range(1,maxconn+1): + tag = "files.%s,%s,%d" % (prefix, relay, cps) + sys.stderr.write(tag + "\n") + try: + client = c_mcurl(prefix, cps, proxyaddr) + monitor(report, tag, mtime) + finally: + if client is not None: + client.terminate() + client.wait() + client = None
if __name__ == '__main__': - sys.stdout.write("benchmark,relay,cap,obs,up,down\n") - bench_fixedrate_direct(sys.stdout) - bench_fixedrate_tor(sys.stdout) - bench_files_direct(sys.stdout, "fixed", 120) - bench_files_tor(sys.stdout, "fixed", 120) - bench_files_direct(sys.stdout, "pareto", 80) - bench_files_tor(sys.stdout, "pareto", 80) + r = sys.stdout + r.write("benchmark,relay,cap,obs,up,down\n") + + t_direct(r, bench_fixedrate, 700, 10, 20) + t_direct(r, bench_files, "fixed", 120, 20) + t_direct(r, bench_files, "pareto", 120, 20) + + t_tor(r, bench_fixedrate, 700, 10, 20) + t_tor(r, bench_files, "fixed", 120, 20) + t_tor(r, bench_files, "pareto", 120, 20) + + t_storus(r, bench_fixedrate, "http", 700, 10, 30) + t_storus(r, bench_files, "http", "fixed", 120, 30) + t_storus(r, bench_files, "http", "pareto", 120, 30) diff --git a/scripts/bm-tor-controller.py b/scripts/bm-tor-controller.py index 1b147be..f10d8d2 100755 --- a/scripts/bm-tor-controller.py +++ b/scripts/bm-tor-controller.py @@ -1,76 +1,86 @@ #! /usr/bin/python
from torctl import TorCtl, TorUtil, PathSupport - +import sys import time
-i = PathSupport.IdHexRestriction - -# in San Francisco -amunet = PathSupport.OrNodeRestriction([ - i('$0CE3CFB1E9CC47B63EA8869813BF6FAB7D4540C1'), # amunet4 - i('$E0BD57A11F00041A9789577C53A1B784473669E4'), # amunet3 - i('$E5E3E9A472EAF7BE9682B86E92305DB4C71048EF') # amunet2 -]) - -# probably in L.A. -hazare = PathSupport.OrNodeRestriction([ - i('$3D0FAFB36EB9FC9D1EFD68758E2B0025117D3D1B'), # hazare2 - i('$6586CEE14353DD1E6FAF3F172A23B00119A67C57'), # saeed - i('$6F383C2629471E1AE7DA053D04625AAED69844CC') # hazare -]) - -# very likely in L.A. -noisebr = PathSupport.OrNodeRestriction([ - i('$3A415473854F9F082F16EECDFE436218FE1169EA'), # noiseexit01c - i('$9C98B38FE270546C69205E16047B8D46BBBB0447'), # noiseexit01d - i('$F97F3B153FED6604230CD497A3D1E9815B007636') # noiseexit01a -]) - -# I shouldn't have to do this -class TheseUniformly(PathSupport.BaseSelectionManager): - def __init__(self, res_entry, res_mid, res_exit): +#i = PathSupport.IdHexRestriction + +#nodes_entry = PathSupport.OrNodeRestriction([ +# i('$580075B70F4CBA0C6819819CC3CB7F4D5D06F0FD') # torEFF +# i('$0CE3CFB1E9CC47B63EA8869813BF6FAB7D4540C1'), # amunet4 +# i('$E0BD57A11F00041A9789577C53A1B784473669E4'), # amunet3 +# i('$E5E3E9A472EAF7BE9682B86E92305DB4C71048EF') # amunet2 +#]) + +#nodes_mid = PathSupport.OrNodeRestriction([ +# i('$204C0D7C6E1D06D7645B07F9BEAC9971DBD7E5EC') # ITM +# i('$3D0FAFB36EB9FC9D1EFD68758E2B0025117D3D1B'), # hazare2 +# i('$6586CEE14353DD1E6FAF3F172A23B00119A67C57'), # saeed +# i('$6F383C2629471E1AE7DA053D04625AAED69844CC') # hazare +#]) + +#nodes_exit = PathSupport.OrNodeRestriction([ +# i('$13A742728E5E0FC7FE363A07799F0FAD276DED43') # Goodnet01 +# i('$3A415473854F9F082F16EECDFE436218FE1169EA'), # noiseexit01c +# i('$9C98B38FE270546C69205E16047B8D46BBBB0447'), # noiseexit01d +# i('$F97F3B153FED6604230CD497A3D1E9815B007636') # noiseexit01a +#]) + +def ensure_nrl(x): + if not isinstance(x, PathSupport.NodeRestrictionList): + x = PathSupport.NodeRestrictionList([x]) + return x + +class ThisSequenceUniformly(PathSupport.BaseSelectionManager): + def __init__(self, restrictions): PathSupport.BaseSelectionManager.__init__(self) - if not isinstance(res_entry, PathSupport.NodeRestrictionList): - res_entry = PathSupport.NodeRestrictionList([res_entry]) - if not isinstance(res_mid, PathSupport.NodeRestrictionList): - res_mid = PathSupport.NodeRestrictionList([res_mid]) - if not isinstance(res_exit, PathSupport.NodeRestrictionList): - res_exit = PathSupport.NodeRestrictionList([res_exit]) - self.res_entry = res_entry - self.res_mid = res_mid - self.res_exit = res_exit - self.path_selector = None + self.restrictions = [ ensure_nrl(x) for x in restrictions ] + self.generators = None
def reconfigure(self, consensus): - if self.path_selector is not None: + if self.generators is not None: try: - self.path_selector.rebuild_gens(consensus.sorted_r) - except NoNodesRemain: - pass + for g in self.generators: + g.rebuild(consensus.sorted_r) + except PathSupport.NoNodesRemain: + pass # have to make new generators
- self.path_selector = PathSupport.PathSelector( - PathSupport.ExactUniformGenerator(consensus.sorted_r, self.res_entry), - PathSupport.ExactUniformGenerator(consensus.sorted_r, self.res_mid), - PathSupport.ExactUniformGenerator(consensus.sorted_r, self.res_exit), - PathSupport.PathRestrictionList([PathSupport.UniqueRestriction()])) + self.generators = [ + PathSupport.ExactUniformGenerator(consensus.sorted_r, restr) + for restr in self.restrictions + ]
def new_consensus(self, consensus): self.reconfigure(consensus)
- def set_exit(self, exit_name): - pass - - def set_target(self, host, port): - pass + def select_path(self): + if self.generators is None: raise PathSupport.NoNodesRemain + path = [] + for g in self.generators: + g.rewind() + r = g.generate().next() + r.refcount += 1 + path.append(r) + return path + +class ThisBridgeAndNothingElse(PathSupport.BaseSelectionManager): + def __init__(self, bridge): + self.bridge = bridge
def select_path(self): - return self.path_selector.select_path(3) + self.bridge.refcount += 1 + return [self.bridge]
TorUtil.loglevel = "WARN"
-s = TheseUniformly(amunet, hazare, noisebr) -c = TorCtl.connect(ConnClass=PathSupport.Connection) +c = TorCtl.connect(ConnClass=PathSupport.Connection) +bs = c.get_network_status("purpose/bridge") +while len(bs) == 0: + bs = c.get_network_status("purpose/bridge") + +s = ThisBridgeAndNothingElse(c.get_router(bs[0])) + h = PathSupport.PathBuilder(c, s) c.set_event_handler(h) c.set_events([TorCtl.EVENT_TYPE.STREAM,
tor-commits@lists.torproject.org