]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/test/check_speed.py
84c21d47a1c5dbf8ef0f21d5ced851460e4617f4
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / check_speed.py
1 #! /usr/bin/env python
2
3 import os, sys
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
8
9 MB = 1000000
10
11 class SpeedTest:
12     DO_IMMUTABLE = True
13     DO_MUTABLE_CREATE = True
14     DO_MUTABLE = True
15
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()
21         f.close()
22         self.base_service = service.MultiService()
23         self.failed = None
24         self.upload_times = {}
25         self.download_times = {}
26
27     def run(self):
28         print "STARTING"
29         d = fireEventually()
30         d.addCallback(lambda res: self.setUp())
31         d.addCallback(lambda res: self.do_test())
32         d.addBoth(self.tearDown)
33         def _err(err):
34             self.failed = err
35             log.err(err)
36             print err
37         d.addErrback(_err)
38         def _done(res):
39             reactor.stop()
40             return res
41         d.addBoth(_done)
42         reactor.run()
43         if self.failed:
44             print "EXCEPTION"
45             print self.failed
46             sys.exit(1)
47
48     def setUp(self):
49         self.base_service.startService()
50         self.tub = Tub()
51         self.tub.setOption("expose-remote-exception-types", False)
52         self.tub.setServiceParent(self.base_service)
53         d = self.tub.getReference(self.control_furl)
54         def _gotref(rref):
55             self.client_rref = rref
56             print "Got Client Control reference"
57             return self.stall(5)
58         d.addCallback(_gotref)
59         return d
60
61     def stall(self, delay, result=None):
62         d = defer.Deferred()
63         reactor.callLater(delay, d.callback, result)
64         return d
65
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
69
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)
78         return d
79
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")
83         def _got(res):
84             assert len(res) # need at least one peer
85             times = res.values()
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
93         d.addCallback(_got)
94         return d
95
96     def do_test(self):
97         print "doing test"
98         rr = self.client_rref
99         d = defer.succeed(None)
100         d.addCallback(self.one_test, "startup", 1, 1000, False) #ignore this one
101         d.addCallback(self.measure_rtt)
102
103         if self.DO_IMMUTABLE:
104             # immutable files
105             d.addCallback(self.one_test, "1x 200B", 1, 200, False)
106             d.addCallback(self.one_test, "10x 200B", 10, 200, False)
107             def _maybe_do_100x_200B(res):
108                 if self.upload_times["10x 200B"] < 5:
109                     print "10x 200B test went too fast, doing 100x 200B test"
110                     return self.one_test(None, "100x 200B", 100, 200, False)
111                 return
112             d.addCallback(_maybe_do_100x_200B)
113             d.addCallback(self.one_test, "1MB", 1, 1*MB, False)
114             d.addCallback(self.one_test, "10MB", 1, 10*MB, False)
115             def _maybe_do_100MB(res):
116                 if self.upload_times["10MB"] > 30:
117                     print "10MB test took too long, skipping 100MB test"
118                     return
119                 return self.one_test(None, "100MB", 1, 100*MB, False)
120             d.addCallback(_maybe_do_100MB)
121
122         if self.DO_MUTABLE_CREATE:
123             # mutable file creation
124             d.addCallback(self.one_test, "10x 200B SSK creation", 10, 200,
125                           "create")
126
127         if self.DO_MUTABLE:
128             # mutable file upload/download
129             d.addCallback(self.one_test, "10x 200B SSK", 10, 200, "upload")
130             def _maybe_do_100x_200B_SSK(res):
131                 if self.upload_times["10x 200B SSK"] < 5:
132                     print "10x 200B SSK test went too fast, doing 100x 200B SSK"
133                     return self.one_test(None, "100x 200B SSK", 100, 200,
134                                          "upload")
135                 return
136             d.addCallback(_maybe_do_100x_200B_SSK)
137             d.addCallback(self.one_test, "1MB SSK", 1, 1*MB, "upload")
138
139         d.addCallback(self.calculate_speeds)
140         return d
141
142     def calculate_speeds(self, res):
143         # time = A*size+B
144         # we assume that A*200bytes is negligible
145
146         if self.DO_IMMUTABLE:
147             # upload
148             if "100x 200B" in self.upload_times:
149                 B = self.upload_times["100x 200B"] / 100
150             else:
151                 B = self.upload_times["10x 200B"] / 10
152             print "upload per-file time: %.3fs" % B
153             print "upload per-file times-avg-RTT: %f" % (B / self.average_rtt)
154             print "upload per-file times-total-RTT: %f" % (B / self.total_rtt)
155             A1 = 1*MB / (self.upload_times["1MB"] - B) # in bytes per second
156             print "upload speed (1MB):", self.number(A1, "Bps")
157             A2 = 10*MB / (self.upload_times["10MB"] - B)
158             print "upload speed (10MB):", self.number(A2, "Bps")
159             if "100MB" in self.upload_times:
160                 A3 = 100*MB / (self.upload_times["100MB"] - B)
161                 print "upload speed (100MB):", self.number(A3, "Bps")
162
163             # download
164             if "100x 200B" in self.download_times:
165                 B = self.download_times["100x 200B"] / 100
166             else:
167                 B = self.download_times["10x 200B"] / 10
168             print "download per-file time: %.3fs" % B
169             print "download per-file times-avg-RTT: %f" % (B / self.average_rtt)
170             print "download per-file times-total-RTT: %f" % (B / self.total_rtt)
171             A1 = 1*MB / (self.download_times["1MB"] - B) # in bytes per second
172             print "download speed (1MB):", self.number(A1, "Bps")
173             A2 = 10*MB / (self.download_times["10MB"] - B)
174             print "download speed (10MB):", self.number(A2, "Bps")
175             if "100MB" in self.download_times:
176                 A3 = 100*MB / (self.download_times["100MB"] - B)
177                 print "download speed (100MB):", self.number(A3, "Bps")
178
179         if self.DO_MUTABLE_CREATE:
180             # SSK creation
181             B = self.upload_times["10x 200B SSK creation"] / 10
182             print "create per-file time SSK: %.3fs" % B
183
184         if self.DO_MUTABLE:
185             # upload SSK
186             if "100x 200B SSK" in self.upload_times:
187                 B = self.upload_times["100x 200B SSK"] / 100
188             else:
189                 B = self.upload_times["10x 200B SSK"] / 10
190             print "upload per-file time SSK: %.3fs" % B
191             A1 = 1*MB / (self.upload_times["1MB SSK"] - B) # in bytes per second
192             print "upload speed SSK (1MB):", self.number(A1, "Bps")
193
194             # download SSK
195             if "100x 200B SSK" in self.download_times:
196                 B = self.download_times["100x 200B SSK"] / 100
197             else:
198                 B = self.download_times["10x 200B SSK"] / 10
199             print "download per-file time SSK: %.3fs" % B
200             A1 = 1*MB / (self.download_times["1MB SSK"] - B) # in bytes per
201                                                              # second
202             print "download speed SSK (1MB):", self.number(A1, "Bps")
203
204     def number(self, value, suffix=""):
205         scaling = 1
206         if value < 1:
207             fmt = "%1.2g%s"
208         elif value < 100:
209             fmt = "%.1f%s"
210         elif value < 1000:
211             fmt = "%d%s"
212         elif value < 1e6:
213             fmt = "%.2fk%s"; scaling = 1e3
214         elif value < 1e9:
215             fmt = "%.2fM%s"; scaling = 1e6
216         elif value < 1e12:
217             fmt = "%.2fG%s"; scaling = 1e9
218         elif value < 1e15:
219             fmt = "%.2fT%s"; scaling = 1e12
220         elif value < 1e18:
221             fmt = "%.2fP%s"; scaling = 1e15
222         else:
223             fmt = "huge! %g%s"
224         return fmt % (value / scaling, suffix)
225
226     def tearDown(self, res):
227         d = self.base_service.stopService()
228         d.addCallback(lambda ignored: res)
229         return d
230
231
232 if __name__ == '__main__':
233     test_client_dir = sys.argv[1]
234     st = SpeedTest(test_client_dir)
235     st.run()