forked from marshmallow-code/marshmallow
-
Notifications
You must be signed in to change notification settings - Fork 2
/
benchmark.py
146 lines (118 loc) · 3.96 KB
/
benchmark.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
"""Simple benchmark for Marshmallow serialization of a moderately complex object.
Uses the `timeit` module to benchmark serializing an object through Marshmallow.
"""
from __future__ import print_function, unicode_literals, division
import argparse
import cProfile
import gc
import timeit
import time
from marshmallow import Schema, fields, ValidationError, pre_load
# Custom validator
def must_not_be_blank(data):
if not data:
raise ValidationError('Data not provided.')
class AuthorSchema(Schema):
id = fields.Int(dump_only=True)
first = fields.Str()
last = fields.Str()
book_count = fields.Float()
age = fields.Float()
address = fields.Str()
full_name = fields.Method('full_name')
def full_name(self, obj):
return obj.first + ' ' + obj.last
def format_name(self, author):
return '{}, {}'.format(author.last, author.first)
class QuoteSchema(Schema):
id = fields.Int(dump_only=True)
author = fields.Nested(AuthorSchema, validate=must_not_be_blank)
content = fields.Str(required=True, validate=must_not_be_blank)
posted_at = fields.Int(dump_only=True)
book_name = fields.Str()
page_number = fields.Float()
line_number = fields.Float()
col_number = fields.Float()
# Allow client to pass author's full name in request body
# e.g. {"author': 'Tim Peters"} rather than {"first": "Tim", "last": "Peters"}
@pre_load
def process_author(self, data):
author_name = data.get('author')
if author_name:
first, last = author_name.split(' ')
author_dict = dict(first=first, last=last)
else:
author_dict = {}
data['author'] = author_dict
return data
class Author:
def __init__(self, id, first, last, book_count, age, address):
self.id = id
self.first = first
self.last = last
self.book_count = book_count
self.age = age
self.address = address
class Quote:
def __init__(
self, id, author, content, posted_at, book_name, page_number,
line_number, col_number,
):
self.id = id
self.author = author
self.content = content
self.posted_at = posted_at
self.book_name = book_name
self.page_number = page_number
self.line_number = line_number
self.col_number = col_number
def run_timeit(quotes, iterations, repeat, profile=False):
quotes_schema = QuoteSchema(many=True)
if profile:
profile = cProfile.Profile()
profile.enable()
gc.collect()
best = min(timeit.repeat(
lambda: quotes_schema.dump(quotes),
'gc.enable()',
number=iterations,
repeat=repeat,
))
if profile:
profile.disable()
profile.dump_stats('marshmallow.pprof')
usec = best * 1e6 / iterations
return usec
def main():
parser = argparse.ArgumentParser(description='Runs a benchmark of Marshmallow.')
parser.add_argument(
'--iterations', type=int, default=1000,
help='Number of iterations to run per test.',
)
parser.add_argument(
'--repeat', type=int, default=5,
help='Number of times to repeat the performance test. The minimum will '
'be used.',
)
parser.add_argument(
'--object-count', type=int, default=20,
help='Number of objects to dump.',
)
parser.add_argument(
'--profile', action='store_true',
help='Whether or not to profile Marshmallow while running the benchmark.',
)
args = parser.parse_args()
quotes = []
for i in range(args.object_count):
quotes.append(
Quote(
i, Author(i, 'Foo', 'Bar', 42, 66, '123 Fake St'),
'Hello World', time.time(), 'The World', 34, 3, 70,
),
)
print('Benchmark Result: {:.2f} usec/dump'.format(
run_timeit(quotes, args.iterations, args.repeat, profile=args.profile),
))
if __name__ == '__main__':
main()