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