blob: 80a4932fa173f91db3fd018db13e5de9d632bb95 [file] [log] [blame]
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +09001#!/usr/bin/env python
2
3#
4# Licensed to the Apache Software Foundation (ASF) under one
5# or more contributor license agreements. See the NOTICE file
6# distributed with this work for additional information
7# regarding copyright ownership. The ASF licenses this file
8# to you under the Apache License, Version 2.0 (the
9# "License"); you may not use this file except in compliance
10# with the License. You may obtain a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing,
15# software distributed under the License is distributed on an
16# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17# KIND, either express or implied. See the License for the
18# specific language governing permissions and limitations
19# under the License.
20#
21
22r"""
23PYTHONPATH=./gen-py:../../lib/py/build/lib... ./FastbinaryTest.py
24"""
25
26# TODO(dreiss): Test error cases. Check for memory leaks.
27
28import math
29import timeit
30
31from copy import deepcopy
32from pprint import pprint
33
34from thrift.transport import TTransport
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090035from thrift.protocol.TBinaryProtocol import TBinaryProtocol, TBinaryProtocolAccelerated
36from thrift.protocol.TCompactProtocol import TCompactProtocol, TCompactProtocolAccelerated
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +090037
38from DebugProtoTest import Srv
39from DebugProtoTest.ttypes import Backwards, Bonk, Empty, HolyMoley, OneOfEach, RandomStuff, Wrapper
40
41
42class TDevNullTransport(TTransport.TTransportBase):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090043 def __init__(self):
44 pass
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +090045
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090046 def isOpen(self):
47 return True
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +090048
James E. King, III0ad20bd2017-09-30 15:44:16 -070049
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +090050ooe1 = OneOfEach()
51ooe1.im_true = True
52ooe1.im_false = False
53ooe1.a_bite = 0xd6
54ooe1.integer16 = 27000
55ooe1.integer32 = 1 << 24
56ooe1.integer64 = 6000 * 1000 * 1000
57ooe1.double_precision = math.pi
58ooe1.some_characters = "Debug THIS!"
Nobuaki Sukegawaa3b88a02016-01-06 20:44:17 +090059ooe1.zomg_unicode = u"\xd7\n\a\t"
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +090060
61ooe2 = OneOfEach()
62ooe2.integer16 = 16
63ooe2.integer32 = 32
64ooe2.integer64 = 64
65ooe2.double_precision = (math.sqrt(5) + 1) / 2
66ooe2.some_characters = ":R (me going \"rrrr\")"
Alexandre Detisted0787212024-12-26 02:44:13 +010067ooe2.zomg_unicode = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"\
68 "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe"\
69 "\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"\
70 "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba"\
71 "\xc7\x83\xe2\x80\xbc"
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +090072
73hm = HolyMoley(**{"big": [], "contain": set(), "bonks": {}})
74hm.big.append(ooe1)
75hm.big.append(ooe2)
76hm.big[0].a_bite = 0x22
77hm.big[1].a_bite = 0x22
78
79hm.contain.add(("and a one", "and a two"))
80hm.contain.add(("then a one, two", "three!", "FOUR!"))
Alexandre Detisted0787212024-12-26 02:44:13 +010081hm.contain.add(("\xd7\n\a\t",))
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +090082hm.contain.add(())
83
84hm.bonks["nothing"] = []
85hm.bonks["something"] = [
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090086 Bonk(**{"type": 1, "message": "Wait."}),
87 Bonk(**{"type": 2, "message": "What?"}),
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +090088]
89hm.bonks["poe"] = [
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090090 Bonk(**{"type": 3, "message": "quoth"}),
91 Bonk(**{"type": 4, "message": "the raven"}),
92 Bonk(**{"type": 5, "message": "nevermore"}),
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +090093]
94
95rs = RandomStuff()
96rs.a = 1
97rs.b = 2
98rs.c = 3
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090099rs.myintlist = list(range(20))
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900100rs.maps = {1: Wrapper(**{"foo": Empty()}), 2: Wrapper(**{"foo": Empty()})}
101rs.bigint = 124523452435
102rs.triple = 3.14
103
104# make sure this splits two buffers in a buffered protocol
105rshuge = RandomStuff()
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900106rshuge.myintlist = list(range(10000))
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900107
108my_zero = Srv.Janky_result(**{"success": 5})
109
110
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900111class Test(object):
112 def __init__(self, fast, slow):
113 self._fast = fast
114 self._slow = slow
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900115
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900116 def _check_write(self, o):
117 trans_fast = TTransport.TMemoryBuffer()
118 trans_slow = TTransport.TMemoryBuffer()
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900119 prot_fast = self._fast(trans_fast, fallback=False)
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900120 prot_slow = self._slow(trans_slow)
121
122 o.write(prot_fast)
123 o.write(prot_slow)
124 ORIG = trans_slow.getvalue()
125 MINE = trans_fast.getvalue()
126 if ORIG != MINE:
127 print("actual : %s\nexpected: %s" % (repr(MINE), repr(ORIG)))
128 raise Exception('write value mismatch')
129
130 def _check_read(self, o):
131 prot = self._slow(TTransport.TMemoryBuffer())
132 o.write(prot)
133
134 slow_version_binary = prot.trans.getvalue()
135
136 prot = self._fast(
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900137 TTransport.TMemoryBuffer(slow_version_binary), fallback=False)
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900138 c = o.__class__()
139 c.read(prot)
140 if c != o:
141 print("actual : ")
142 pprint(repr(c))
143 print("expected: ")
144 pprint(repr(o))
145 raise Exception('read value mismatch')
146
147 prot = self._fast(
148 TTransport.TBufferedTransport(
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900149 TTransport.TMemoryBuffer(slow_version_binary)), fallback=False)
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900150 c = o.__class__()
151 c.read(prot)
152 if c != o:
153 print("actual : ")
154 pprint(repr(c))
155 print("expected: ")
156 pprint(repr(o))
157 raise Exception('read value mismatch')
158
159 def do_test(self):
160 self._check_write(HolyMoley())
161 self._check_read(HolyMoley())
162
163 self._check_write(hm)
164 no_set = deepcopy(hm)
165 no_set.contain = set()
166 self._check_read(no_set)
167 self._check_read(hm)
168
169 self._check_write(rs)
170 self._check_read(rs)
171
172 self._check_write(rshuge)
173 self._check_read(rshuge)
174
175 self._check_write(my_zero)
176 self._check_read(my_zero)
177
178 self._check_read(Backwards(**{"first_tag2": 4, "second_tag1": 2}))
179
180 # One case where the serialized form changes, but only superficially.
181 o = Backwards(**{"first_tag2": 4, "second_tag1": 2})
182 trans_fast = TTransport.TMemoryBuffer()
183 trans_slow = TTransport.TMemoryBuffer()
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900184 prot_fast = self._fast(trans_fast, fallback=False)
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900185 prot_slow = self._slow(trans_slow)
186
187 o.write(prot_fast)
188 o.write(prot_slow)
189 ORIG = trans_slow.getvalue()
190 MINE = trans_fast.getvalue()
191 assert id(ORIG) != id(MINE)
192
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900193 prot = self._fast(TTransport.TMemoryBuffer(), fallback=False)
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900194 o.write(prot)
195 prot = self._slow(
196 TTransport.TMemoryBuffer(prot.trans.getvalue()))
197 c = o.__class__()
198 c.read(prot)
199 if c != o:
200 print("copy: ")
201 pprint(repr(c))
202 print("orig: ")
203 pprint(repr(o))
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900204
205
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900206def do_test(fast, slow):
207 Test(fast, slow).do_test()
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900208
209
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900210def do_benchmark(protocol, iters=5000, skip_slow=False):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900211 setup = """
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900212from __main__ import hm, rs, TDevNullTransport
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900213from thrift.protocol.{0} import {0}{1}
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900214trans = TDevNullTransport()
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900215prot = {0}{1}(trans{2})
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900216"""
217
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900218 setup_fast = setup.format(protocol, 'Accelerated', ', fallback=False')
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900219 if not skip_slow:
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900220 setup_slow = setup.format(protocol, '', '')
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900221
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900222 print("Starting Benchmarks")
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900223
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900224 if not skip_slow:
225 print("HolyMoley Standard = %f" %
226 timeit.Timer('hm.write(prot)', setup_slow).timeit(number=iters))
227
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900228 print("HolyMoley Acceler. = %f" %
229 timeit.Timer('hm.write(prot)', setup_fast).timeit(number=iters))
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900230
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900231 if not skip_slow:
232 print("FastStruct Standard = %f" %
233 timeit.Timer('rs.write(prot)', setup_slow).timeit(number=iters))
234
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900235 print("FastStruct Acceler. = %f" %
236 timeit.Timer('rs.write(prot)', setup_fast).timeit(number=iters))
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900237
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900238
Nobuaki Sukegawa7b894692015-12-23 21:45:06 +0900239if __name__ == '__main__':
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900240 print('Testing TBinaryAccelerated')
241 do_test(TBinaryProtocolAccelerated, TBinaryProtocol)
242 do_benchmark('TBinaryProtocol')
243 print('Testing TCompactAccelerated')
244 do_test(TCompactProtocolAccelerated, TCompactProtocol)
245 do_benchmark('TCompactProtocol')