blob: d7ddbfc3cc6b4044c52bd28ab63d46dcf6385214 [file] [log] [blame]
Zsolt Harasztia54f2ac2016-09-21 15:54:15 -07001#!/usr/bin/env python
2
3"""
4We use this module to time-test various alternatives for building,
5serializing, and de-serializing objects.
6"""
7
8import time
9from copy import copy, deepcopy
10
11import addressbook_pb2
12from random import randint
13from uuid import uuid4
14from simplejson import dumps, loads, JSONEncoder
15
16
17class ProtoBufs(object):
18
19 FILENAME = 'addressbook.bin.pb'
20
21 @staticmethod
22 def makeAddressBook(n):
23
24 addressbook = addressbook_pb2.AddressBook()
25
26 for i in xrange(n):
27 person = addressbook.people.add()
28 person.id = i
29 person.name = uuid4().get_hex()
30 person.email = person.name + '@abc.com'
31
32 phone1 = person.phones.add()
33 phone1.number = str(randint(1000000000, 7999999999))
34 phone1.type = addressbook_pb2.Person.HOME
35
36 phone2 = person.phones.add()
37 phone2.number = str(randint(1000000000, 7999999999))
38 phone2.type = addressbook_pb2.Person.MOBILE
39
40 return addressbook
41
42 @staticmethod
43 def serialize(addressbook):
44 return addressbook.SerializeToString()
45
46 @staticmethod
47 def deserialize(str):
48 addressbook = addressbook_pb2.AddressBook()
49 addressbook.ParseFromString(str)
50 return addressbook
51
52 @staticmethod
53 def diff(addressbook1, addressbook2):
54 assert isinstance(addressbook1, addressbook_pb2.AddressBook)
55 assert isinstance(addressbook2, addressbook_pb2.AddressBook)
56 assert addressbook1 == addressbook2
57
58
59class JsonWithPythonData(object):
60
61 FILENAME = 'addressbook.native.json'
62
63 @staticmethod
64 def makeAddressBook(n):
65
66 addressbook = dict(people=[])
67 people = addressbook['people']
68
69 for i in xrange(n):
70 name = uuid4().get_hex()
71 people.append(dict(
72 id=i,
73 name=name,
74 email=name + '@abc.com',
75 phones=[
76 dict(
77 number=str(randint(1000000000, 7999999999)),
78 type='HOME'
79 ),
80 dict(
81 number=str(randint(1000000000, 7999999999)),
82 type='MOBILE'
83 )
84 ]
85 ))
86
87 return addressbook
88
89 @staticmethod
90 def serialize(addressbook):
91 return dumps(addressbook)
92
93 @staticmethod
94 def deserialize(str):
95 return loads(str)
96
97 @staticmethod
98 def diff(addressbook1, addressbook2):
99 assert isinstance(addressbook1, dict)
100 assert isinstance(addressbook2, dict)
101 assert addressbook1 == addressbook2
102
103
104class JsonWithPythonClasses(object):
105
106 class JsonEncoded(object):
107 def __eq__(self, other):
108 return self.__dict__ == other.__dict__
109
110 class Phone(JsonEncoded):
111
112 def __init__(self, number, type):
113 self.number = number
114 self.type = type
115
116 @property
117 def number(self):
118 return self._type
119 @number.setter
120 def number(self, number):
121 assert isinstance(number, str)
122 self._number = number
123
124 @property
125 def type(self):
126 return self._type
127 @number.setter
128 def type(self, type):
129 assert isinstance(type, str)
130 self._type = type
131
132 class Person(JsonEncoded):
133
134 def __init__(self, id, name, email, phones=list()):
135 self.id = id
136 self.name = name
137 self.email = email
138 self.phones = phones
139
140 @property
141 def id(self):
142 return self._id
143 @id.setter
144 def id(self, id):
145 assert isinstance(id, int)
146 self._id = id
147
148 @property
149 def name(self):
150 return self._name
151 @name.setter
152 def name(self, name):
153 assert isinstance(name, str)
154 self._name = name
155
156 @property
157 def email(self):
158 return self._email
159 @email.setter
160 def email(self, email):
161 assert isinstance(email, str)
162 self._email = email
163
164 @property
165 def phones(self):
166 return self._phones
167 @phones.setter
168 def phones(self, phones):
169 assert isinstance(phones, list)
170 self._phones = phones
171
172
173 class AddressBook(JsonEncoded):
174
175 def __init__(self, people=list()):
176 self.people = people
177
178 @property
179 def people(self):
180 return self._people
181 @people.setter
182 def people(self, people):
183 assert isinstance(people, list)
184 self._people = people
185
186 cls_map = {
187 Phone.__name__: Phone,
188 Person.__name__: Person,
189 AddressBook.__name__: AddressBook
190 }
191
192 class CustomEncoder(JSONEncoder):
193 def default(self, o):
194 if isinstance(o, JsonWithPythonClasses.JsonEncoded):
195 d = dict((k.strip('_'), v) for k, v in o.__dict__.iteritems())
196 d['_class'] = o.__class__.__name__
197 return d
198 return super(self).default(o)
199
200 @staticmethod
201 def as_object(dct):
202 if '_class' in dct and dct['_class'] in JsonWithPythonClasses.cls_map:
203 kw = deepcopy(dct)
204 cls_name = kw.pop('_class')
205 cls = JsonWithPythonClasses.cls_map[cls_name]
206 return cls(**kw)
207 return dct
208
209 FILENAME = 'addressbook.class.json'
210
211 @staticmethod
212 def makeAddressBook(n):
213
214 addressbook = JsonWithPythonClasses.AddressBook()
215 people = addressbook.people
216
217 for i in xrange(n):
218 name = uuid4().get_hex()
219 person = JsonWithPythonClasses.Person(
220 id=i,
221 name=name,
222 email=name + '@abc.com',
223 phones=[
224 JsonWithPythonClasses.Phone(
225 number=str(randint(1000000000, 7999999999)),
226 type='HOME'
227 ),
228 JsonWithPythonClasses.Phone(
229 number=str(randint(1000000000, 7999999999)),
230 type='MOBILE'
231 )
232 ]
233 )
234 people.append(person)
235
236 return addressbook
237
238 @staticmethod
239 def serialize(addressbook):
240 return dumps(addressbook, cls=JsonWithPythonClasses.CustomEncoder)
241
242 @staticmethod
243 def deserialize(str):
244 return loads(str, object_hook=JsonWithPythonClasses.as_object)
245
246 @staticmethod
247 def diff(addressbook1, addressbook2):
248 assert isinstance(addressbook1, JsonWithPythonClasses.AddressBook)
249 assert isinstance(addressbook2, JsonWithPythonClasses.AddressBook)
250 assert len(addressbook1.people) == len(addressbook2.people)
251 for i in xrange(len(addressbook1.people)):
252 assert addressbook1.people[i] == addressbook2.people[i], \
253 '\n%s\n!=\n%s' % (addressbook1.people[i].__dict__,
254 addressbook2.people[i].__dict__)
255 assert addressbook1 == addressbook2
256
257
258def timetest(cls, n):
259
260 generator = cls()
261
262 # generate addressbook
263
264 t = time.time()
265 addressbook = generator.makeAddressBook(n)
266 t_make = time.time() - t
267
268 # serialize addressbook to string and save it to file
269 t = time.time()
270 str = generator.serialize(addressbook)
271 t_serialize = time.time() - t
272 size = len(str)
273
274 with open(cls.FILENAME, 'wb') as f:
275 f.write(str)
276
277 # deserialize by reading it back from file
278 t = time.time()
279 addressbook2 = generator.deserialize(str)
280 t_deserialize = time.time() - t
281
282 generator.diff(addressbook, addressbook2)
283
284 print "%-30s %12lf %12lf %12lf %10d" % \
285 (cls.__name__,
286 1e6 * t_make / n,
287 1e6 * t_serialize / n,
288 1e6 * t_deserialize / n,
289 size / n)
290
291
292def run_tests(n):
293 print "%-30s %12s %12s %12s %10s" % \
294 ('Method', 'Gen [us]', 'Ser [us]', 'Des [us]', 'Size [bytes]')
295 timetest(ProtoBufs, n)
296 timetest(JsonWithPythonData, n)
297 timetest(JsonWithPythonClasses, n)
298
299
300run_tests(10000)