4 from twisted.internet import reactor, defer
5 from twisted.python import log
6 from twisted.application import service
7 from foolscap.api import Tub, fireEventually
13 DO_MUTABLE_CREATE = True
16 def __init__(self, test_client_dir):
17 #self.real_stderr = sys.stderr
18 log.startLogging(open("st.log", "a"), setStdout=False)
19 f = open(os.path.join(test_client_dir, "private", "control.furl"), "r")
20 self.control_furl = f.read().strip()
22 self.base_service = service.MultiService()
24 self.upload_times = {}
25 self.download_times = {}
30 d.addCallback(lambda res: self.setUp())
31 d.addCallback(lambda res: self.do_test())
32 d.addBoth(self.tearDown)
49 self.base_service.startService()
51 self.tub.setOption("expose-remote-exception-types", False)
52 self.tub.setServiceParent(self.base_service)
53 d = self.tub.getReference(self.control_furl)
55 self.client_rref = rref
56 print "Got Client Control reference"
58 d.addCallback(_gotref)
61 def stall(self, delay, result=None):
63 reactor.callLater(delay, d.callback, result)
66 def record_times(self, times, key):
67 print "TIME (%s): %s up, %s down" % (key, times[0], times[1])
68 self.upload_times[key], self.download_times[key] = times
70 def one_test(self, res, name, count, size, mutable):
71 # values for 'mutable':
72 # False (upload a different CHK file for each 'count')
73 # "create" (upload different contents into a new SSK file)
74 # "upload" (upload different contents into the same SSK file. The
75 # time consumed does not include the creation of the file)
76 d = self.client_rref.callRemote("speed_test", count, size, mutable)
77 d.addCallback(self.record_times, name)
80 def measure_rtt(self, res):
81 # use RIClient.get_nodeid() to measure the foolscap-level RTT
82 d = self.client_rref.callRemote("measure_peer_response_time")
84 assert len(res) # need at least one peer
86 self.total_rtt = sum(times)
87 self.average_rtt = sum(times) / len(times)
88 self.max_rtt = max(times)
89 print "num-peers: %d" % len(times)
90 print "total-RTT: %f" % self.total_rtt
91 print "average-RTT: %f" % self.average_rtt
92 print "max-RTT: %f" % self.max_rtt
98 d = defer.succeed(None)
99 d.addCallback(self.one_test, "startup", 1, 1000, False) #ignore this one
100 d.addCallback(self.measure_rtt)
102 if self.DO_IMMUTABLE:
104 d.addCallback(self.one_test, "1x 200B", 1, 200, False)
105 d.addCallback(self.one_test, "10x 200B", 10, 200, False)
106 def _maybe_do_100x_200B(res):
107 if self.upload_times["10x 200B"] < 5:
108 print "10x 200B test went too fast, doing 100x 200B test"
109 return self.one_test(None, "100x 200B", 100, 200, False)
111 d.addCallback(_maybe_do_100x_200B)
112 d.addCallback(self.one_test, "1MB", 1, 1*MB, False)
113 d.addCallback(self.one_test, "10MB", 1, 10*MB, False)
114 def _maybe_do_100MB(res):
115 if self.upload_times["10MB"] > 30:
116 print "10MB test took too long, skipping 100MB test"
118 return self.one_test(None, "100MB", 1, 100*MB, False)
119 d.addCallback(_maybe_do_100MB)
121 if self.DO_MUTABLE_CREATE:
122 # mutable file creation
123 d.addCallback(self.one_test, "10x 200B SSK creation", 10, 200,
127 # mutable file upload/download
128 d.addCallback(self.one_test, "10x 200B SSK", 10, 200, "upload")
129 def _maybe_do_100x_200B_SSK(res):
130 if self.upload_times["10x 200B SSK"] < 5:
131 print "10x 200B SSK test went too fast, doing 100x 200B SSK"
132 return self.one_test(None, "100x 200B SSK", 100, 200,
135 d.addCallback(_maybe_do_100x_200B_SSK)
136 d.addCallback(self.one_test, "1MB SSK", 1, 1*MB, "upload")
138 d.addCallback(self.calculate_speeds)
141 def calculate_speeds(self, res):
143 # we assume that A*200bytes is negligible
145 if self.DO_IMMUTABLE:
147 if "100x 200B" in self.upload_times:
148 B = self.upload_times["100x 200B"] / 100
150 B = self.upload_times["10x 200B"] / 10
151 print "upload per-file time: %.3fs" % B
152 print "upload per-file times-avg-RTT: %f" % (B / self.average_rtt)
153 print "upload per-file times-total-RTT: %f" % (B / self.total_rtt)
154 A1 = 1*MB / (self.upload_times["1MB"] - B) # in bytes per second
155 print "upload speed (1MB):", self.number(A1, "Bps")
156 A2 = 10*MB / (self.upload_times["10MB"] - B)
157 print "upload speed (10MB):", self.number(A2, "Bps")
158 if "100MB" in self.upload_times:
159 A3 = 100*MB / (self.upload_times["100MB"] - B)
160 print "upload speed (100MB):", self.number(A3, "Bps")
163 if "100x 200B" in self.download_times:
164 B = self.download_times["100x 200B"] / 100
166 B = self.download_times["10x 200B"] / 10
167 print "download per-file time: %.3fs" % B
168 print "download per-file times-avg-RTT: %f" % (B / self.average_rtt)
169 print "download per-file times-total-RTT: %f" % (B / self.total_rtt)
170 A1 = 1*MB / (self.download_times["1MB"] - B) # in bytes per second
171 print "download speed (1MB):", self.number(A1, "Bps")
172 A2 = 10*MB / (self.download_times["10MB"] - B)
173 print "download speed (10MB):", self.number(A2, "Bps")
174 if "100MB" in self.download_times:
175 A3 = 100*MB / (self.download_times["100MB"] - B)
176 print "download speed (100MB):", self.number(A3, "Bps")
178 if self.DO_MUTABLE_CREATE:
180 B = self.upload_times["10x 200B SSK creation"] / 10
181 print "create per-file time SSK: %.3fs" % B
185 if "100x 200B SSK" in self.upload_times:
186 B = self.upload_times["100x 200B SSK"] / 100
188 B = self.upload_times["10x 200B SSK"] / 10
189 print "upload per-file time SSK: %.3fs" % B
190 A1 = 1*MB / (self.upload_times["1MB SSK"] - B) # in bytes per second
191 print "upload speed SSK (1MB):", self.number(A1, "Bps")
194 if "100x 200B SSK" in self.download_times:
195 B = self.download_times["100x 200B SSK"] / 100
197 B = self.download_times["10x 200B SSK"] / 10
198 print "download per-file time SSK: %.3fs" % B
199 A1 = 1*MB / (self.download_times["1MB SSK"] - B) # in bytes per
201 print "download speed SSK (1MB):", self.number(A1, "Bps")
203 def number(self, value, suffix=""):
212 fmt = "%.2fk%s"; scaling = 1e3
214 fmt = "%.2fM%s"; scaling = 1e6
216 fmt = "%.2fG%s"; scaling = 1e9
218 fmt = "%.2fT%s"; scaling = 1e12
220 fmt = "%.2fP%s"; scaling = 1e15
223 return fmt % (value / scaling, suffix)
225 def tearDown(self, res):
226 d = self.base_service.stopService()
227 d.addCallback(lambda ignored: res)
231 if __name__ == '__main__':
232 test_client_dir = sys.argv[1]
233 st = SpeedTest(test_client_dir)