blob: d7ddbfc3cc6b4044c52bd28ab63d46dcf6385214 [file] [log] [blame]
#!/usr/bin/env python
"""
We use this module to time-test various alternatives for building,
serializing, and de-serializing objects.
"""
import time
from copy import copy, deepcopy
import addressbook_pb2
from random import randint
from uuid import uuid4
from simplejson import dumps, loads, JSONEncoder
class ProtoBufs(object):
FILENAME = 'addressbook.bin.pb'
@staticmethod
def makeAddressBook(n):
addressbook = addressbook_pb2.AddressBook()
for i in xrange(n):
person = addressbook.people.add()
person.id = i
person.name = uuid4().get_hex()
person.email = person.name + '@abc.com'
phone1 = person.phones.add()
phone1.number = str(randint(1000000000, 7999999999))
phone1.type = addressbook_pb2.Person.HOME
phone2 = person.phones.add()
phone2.number = str(randint(1000000000, 7999999999))
phone2.type = addressbook_pb2.Person.MOBILE
return addressbook
@staticmethod
def serialize(addressbook):
return addressbook.SerializeToString()
@staticmethod
def deserialize(str):
addressbook = addressbook_pb2.AddressBook()
addressbook.ParseFromString(str)
return addressbook
@staticmethod
def diff(addressbook1, addressbook2):
assert isinstance(addressbook1, addressbook_pb2.AddressBook)
assert isinstance(addressbook2, addressbook_pb2.AddressBook)
assert addressbook1 == addressbook2
class JsonWithPythonData(object):
FILENAME = 'addressbook.native.json'
@staticmethod
def makeAddressBook(n):
addressbook = dict(people=[])
people = addressbook['people']
for i in xrange(n):
name = uuid4().get_hex()
people.append(dict(
id=i,
name=name,
email=name + '@abc.com',
phones=[
dict(
number=str(randint(1000000000, 7999999999)),
type='HOME'
),
dict(
number=str(randint(1000000000, 7999999999)),
type='MOBILE'
)
]
))
return addressbook
@staticmethod
def serialize(addressbook):
return dumps(addressbook)
@staticmethod
def deserialize(str):
return loads(str)
@staticmethod
def diff(addressbook1, addressbook2):
assert isinstance(addressbook1, dict)
assert isinstance(addressbook2, dict)
assert addressbook1 == addressbook2
class JsonWithPythonClasses(object):
class JsonEncoded(object):
def __eq__(self, other):
return self.__dict__ == other.__dict__
class Phone(JsonEncoded):
def __init__(self, number, type):
self.number = number
self.type = type
@property
def number(self):
return self._type
@number.setter
def number(self, number):
assert isinstance(number, str)
self._number = number
@property
def type(self):
return self._type
@number.setter
def type(self, type):
assert isinstance(type, str)
self._type = type
class Person(JsonEncoded):
def __init__(self, id, name, email, phones=list()):
self.id = id
self.name = name
self.email = email
self.phones = phones
@property
def id(self):
return self._id
@id.setter
def id(self, id):
assert isinstance(id, int)
self._id = id
@property
def name(self):
return self._name
@name.setter
def name(self, name):
assert isinstance(name, str)
self._name = name
@property
def email(self):
return self._email
@email.setter
def email(self, email):
assert isinstance(email, str)
self._email = email
@property
def phones(self):
return self._phones
@phones.setter
def phones(self, phones):
assert isinstance(phones, list)
self._phones = phones
class AddressBook(JsonEncoded):
def __init__(self, people=list()):
self.people = people
@property
def people(self):
return self._people
@people.setter
def people(self, people):
assert isinstance(people, list)
self._people = people
cls_map = {
Phone.__name__: Phone,
Person.__name__: Person,
AddressBook.__name__: AddressBook
}
class CustomEncoder(JSONEncoder):
def default(self, o):
if isinstance(o, JsonWithPythonClasses.JsonEncoded):
d = dict((k.strip('_'), v) for k, v in o.__dict__.iteritems())
d['_class'] = o.__class__.__name__
return d
return super(self).default(o)
@staticmethod
def as_object(dct):
if '_class' in dct and dct['_class'] in JsonWithPythonClasses.cls_map:
kw = deepcopy(dct)
cls_name = kw.pop('_class')
cls = JsonWithPythonClasses.cls_map[cls_name]
return cls(**kw)
return dct
FILENAME = 'addressbook.class.json'
@staticmethod
def makeAddressBook(n):
addressbook = JsonWithPythonClasses.AddressBook()
people = addressbook.people
for i in xrange(n):
name = uuid4().get_hex()
person = JsonWithPythonClasses.Person(
id=i,
name=name,
email=name + '@abc.com',
phones=[
JsonWithPythonClasses.Phone(
number=str(randint(1000000000, 7999999999)),
type='HOME'
),
JsonWithPythonClasses.Phone(
number=str(randint(1000000000, 7999999999)),
type='MOBILE'
)
]
)
people.append(person)
return addressbook
@staticmethod
def serialize(addressbook):
return dumps(addressbook, cls=JsonWithPythonClasses.CustomEncoder)
@staticmethod
def deserialize(str):
return loads(str, object_hook=JsonWithPythonClasses.as_object)
@staticmethod
def diff(addressbook1, addressbook2):
assert isinstance(addressbook1, JsonWithPythonClasses.AddressBook)
assert isinstance(addressbook2, JsonWithPythonClasses.AddressBook)
assert len(addressbook1.people) == len(addressbook2.people)
for i in xrange(len(addressbook1.people)):
assert addressbook1.people[i] == addressbook2.people[i], \
'\n%s\n!=\n%s' % (addressbook1.people[i].__dict__,
addressbook2.people[i].__dict__)
assert addressbook1 == addressbook2
def timetest(cls, n):
generator = cls()
# generate addressbook
t = time.time()
addressbook = generator.makeAddressBook(n)
t_make = time.time() - t
# serialize addressbook to string and save it to file
t = time.time()
str = generator.serialize(addressbook)
t_serialize = time.time() - t
size = len(str)
with open(cls.FILENAME, 'wb') as f:
f.write(str)
# deserialize by reading it back from file
t = time.time()
addressbook2 = generator.deserialize(str)
t_deserialize = time.time() - t
generator.diff(addressbook, addressbook2)
print "%-30s %12lf %12lf %12lf %10d" % \
(cls.__name__,
1e6 * t_make / n,
1e6 * t_serialize / n,
1e6 * t_deserialize / n,
size / n)
def run_tests(n):
print "%-30s %12s %12s %12s %10s" % \
('Method', 'Gen [us]', 'Ser [us]', 'Des [us]', 'Size [bytes]')
timetest(ProtoBufs, n)
timetest(JsonWithPythonData, n)
timetest(JsonWithPythonClasses, n)
run_tests(10000)