feat: optimize for interfaces added messages (#122)
This commit is contained in:
parent
864843c9e5
commit
c05a27aef9
40
bench/unmarshall_interfaces_added.py
Normal file
40
bench/unmarshall_interfaces_added.py
Normal file
@ -0,0 +1,40 @@
|
||||
import io
|
||||
import timeit
|
||||
|
||||
from dbus_fast._private.unmarshaller import Unmarshaller
|
||||
|
||||
# cythonize -X language_level=3 -a -i src/dbus_fast/_private/unmarshaller.py
|
||||
|
||||
|
||||
bluez_interfaces_added_message = (
|
||||
b'l\4\1\1\240\2\0\0\227\272\23\0u\0\0\0\1\1o\0\1\0\0\0/\0\0\0\0\0\0\0\2\1s\0"\0\0\0'
|
||||
b"org.freedesktop.DBus.ObjectManager\0\0\0\0\0\0\3\1s\0\17\0\0\0InterfacesAdded\0\10"
|
||||
b"\1g\0\noa{sa{sv}}\0\7\1s\0\4\0\0\0:1.4\0\0\0\0%\0\0\0/org/bluez/hci1/dev_58_2D_34"
|
||||
b"_60_26_36\0\0\0p\2\0\0#\0\0\0org.freedesktop.DBus.Introspectable\0\0\0\0\0\0\0\0\0"
|
||||
b"\21\0\0\0org.bluez.Device1\0\0\0\364\1\0\0\0\0\0\0\7\0\0\0Address\0\1s\0\0\21\0\0"
|
||||
b"\00058:2D:34:60:26:36\0\0\0\v\0\0\0AddressType\0\1s\0\0\6\0\0\0public\0\0\4\0\0\0"
|
||||
b"Name\0\1s\0\33\0\0\0Qingping Door/Window Sensor\0\0\0\0\0\5\0\0\0Alias\0\1s\0\0\0"
|
||||
b"\0\33\0\0\0Qingping Door/Window Sensor\0\6\0\0\0Paired\0\1b\0\0\0\0\0\0\0\0\0\0\0"
|
||||
b"\7\0\0\0Trusted\0\1b\0\0\0\0\0\0\0\0\0\0\7\0\0\0Blocked\0\1b\0\0\0\0\0\0\0\0\0\0\r"
|
||||
b"\0\0\0LegacyPairing\0\1b\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0RSSI\0\1n\0\316\377\0\0\t"
|
||||
b"\0\0\0Connected\0\1b\0\0\0\0\0\0\0\0\5\0\0\0UUIDs\0\2as\0\0\0\0\0\0\0\0\0\0\0\7\0"
|
||||
b"\0\0Adapter\0\1o\0\0\17\0\0\0/org/bluez/hci1\0\0\0\0\0\v\0\0\0ServiceData\0\5a{sv}"
|
||||
b"\0\0@\0\0\0\0\0\0\0$\0\0\0000000fe95-0000-1000-8000-00805f9b34fb\0\2ay\0\0\0\0\f\0"
|
||||
b"\0\0000X\326\3\0026&`4-X\10\20\0\0\0ServicesResolved\0\1b\0\0\0\0\0\0\0\0\0\37\0\0"
|
||||
b"\0org.freedesktop.DBus.Properties\0\0\0\0\0"
|
||||
)
|
||||
|
||||
|
||||
stream = io.BytesIO(bluez_interfaces_added_message)
|
||||
unmarshaller = Unmarshaller(stream)
|
||||
|
||||
|
||||
def unmarshall_interfaces_added_message():
|
||||
stream.seek(0)
|
||||
unmarshaller.reset()
|
||||
unmarshaller.unmarshall()
|
||||
|
||||
|
||||
count = 3000000
|
||||
time = timeit.Timer(unmarshall_interfaces_added_message).timeit(count)
|
||||
print(f"Unmarshalling {count} bluetooth InterfacesAdded messages took {time} seconds")
|
||||
@ -41,11 +41,19 @@ cdef object MESSAGE_FLAG_MAP
|
||||
cdef object HEADER_MESSAGE_ARG_NAME
|
||||
|
||||
cdef object SIGNATURE_TREE_EMPTY
|
||||
cdef object SIGNATURE_TREE_B
|
||||
cdef object SIGNATURE_TREE_N
|
||||
cdef object SIGNATURE_TREE_O
|
||||
cdef object SIGNATURE_TREE_S
|
||||
cdef object SIGNATURE_TREE_AS
|
||||
cdef object SIGNATURE_TREE_AS_TYPES_0
|
||||
cdef object SIGNATURE_TREE_A_SV
|
||||
cdef object SIGNATURE_TREE_A_SV_TYPES_0
|
||||
cdef object SIGNATURE_TREE_SA_SV_AS
|
||||
cdef object SIGNATURE_TREE_SA_SV_AS_TYPES_1
|
||||
cdef object SIGNATURE_TREE_SA_SV_AS_TYPES_2
|
||||
cdef object SIGNATURE_TREE_OA_SA_SV
|
||||
cdef object SIGNATURE_TREE_OA_SA_SV_TYPES_1
|
||||
cdef object SIGNATURE_TREE_AY
|
||||
cdef object SIGNATURE_TREE_AY_TYPES_0
|
||||
cdef object SIGNATURE_TREE_A_QV
|
||||
@ -101,6 +109,10 @@ cdef class Unmarshaller:
|
||||
)
|
||||
cdef _read_to_pos(self, unsigned long pos)
|
||||
|
||||
cpdef read_boolean(self, object type_)
|
||||
|
||||
cdef bint _read_boolean(self)
|
||||
|
||||
cpdef read_uint32_unpack(self, object type_)
|
||||
|
||||
cdef unsigned int _read_uint32_unpack(self)
|
||||
|
||||
@ -59,10 +59,17 @@ HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION = 12
|
||||
|
||||
|
||||
SIGNATURE_TREE_EMPTY = get_signature_tree("")
|
||||
SIGNATURE_TREE_B = get_signature_tree("b")
|
||||
SIGNATURE_TREE_N = get_signature_tree("n")
|
||||
SIGNATURE_TREE_S = get_signature_tree("s")
|
||||
SIGNATURE_TREE_O = get_signature_tree("o")
|
||||
|
||||
SIGNATURE_TREE_AY = get_signature_tree("ay")
|
||||
SIGNATURE_TREE_AS = get_signature_tree("as")
|
||||
SIGNATURE_TREE_AS_TYPES_0 = SIGNATURE_TREE_AS.types[0]
|
||||
SIGNATURE_TREE_A_SV = get_signature_tree("a{sv}")
|
||||
SIGNATURE_TREE_A_SV_TYPES_0 = SIGNATURE_TREE_A_SV.types[0]
|
||||
|
||||
SIGNATURE_TREE_AY_TYPES_0 = SIGNATURE_TREE_AY.types[0]
|
||||
SIGNATURE_TREE_A_QV = get_signature_tree("a{qv}")
|
||||
SIGNATURE_TREE_A_QV_TYPES_0 = SIGNATURE_TREE_A_QV.types[0]
|
||||
@ -71,6 +78,9 @@ SIGNATURE_TREE_SA_SV_AS = get_signature_tree("sa{sv}as")
|
||||
SIGNATURE_TREE_SA_SV_AS_TYPES_1 = SIGNATURE_TREE_SA_SV_AS.types[1]
|
||||
SIGNATURE_TREE_SA_SV_AS_TYPES_2 = SIGNATURE_TREE_SA_SV_AS.types[2]
|
||||
|
||||
SIGNATURE_TREE_OA_SA_SV = get_signature_tree("oa{sa{sv}}")
|
||||
SIGNATURE_TREE_OA_SA_SV_TYPES_1 = SIGNATURE_TREE_OA_SA_SV.types[1]
|
||||
|
||||
HEADER_MESSAGE_ARG_NAME = {
|
||||
1: "path",
|
||||
2: "interface",
|
||||
@ -292,6 +302,9 @@ class Unmarshaller:
|
||||
return self._int16_unpack(self._buf, self._pos - INT16_SIZE)[0]
|
||||
|
||||
def read_boolean(self, type_: SignatureType) -> bool:
|
||||
return self._read_boolean()
|
||||
|
||||
def _read_boolean(self) -> bool:
|
||||
return bool(self._read_uint32_unpack())
|
||||
|
||||
def read_string_unpack(self, type_: SignatureType) -> str:
|
||||
@ -338,6 +351,22 @@ class Unmarshaller:
|
||||
self._read_array(SIGNATURE_TREE_A_QV_TYPES_0),
|
||||
False,
|
||||
)
|
||||
elif signature == "s":
|
||||
return Variant(SIGNATURE_TREE_S, self._read_string_unpack(), False)
|
||||
elif signature == "b":
|
||||
return Variant(SIGNATURE_TREE_B, self._read_boolean(), False)
|
||||
elif signature == "o":
|
||||
return Variant(SIGNATURE_TREE_O, self._read_string_unpack(), False)
|
||||
elif signature == "as":
|
||||
return Variant(
|
||||
SIGNATURE_TREE_AS, self._read_array(SIGNATURE_TREE_AS_TYPES_0), False
|
||||
)
|
||||
elif signature == "a{sv}":
|
||||
return Variant(
|
||||
SIGNATURE_TREE_A_SV,
|
||||
self._read_array(SIGNATURE_TREE_A_SV_TYPES_0),
|
||||
False,
|
||||
)
|
||||
tree = get_signature_tree(signature)
|
||||
signature_type = tree.types[0]
|
||||
return Variant(
|
||||
@ -395,20 +424,25 @@ class Unmarshaller:
|
||||
# Strings with variant values are the most common case
|
||||
# so we optimize for that by inlining the string reading
|
||||
# and the variant reading here
|
||||
if child_1_token == "v":
|
||||
if child_0_token in "os":
|
||||
while self._pos - beginning_pos < array_length:
|
||||
self._pos += -self._pos & 7 # align 8
|
||||
key = self._read_string_unpack()
|
||||
result_dict[key] = self._read_variant()
|
||||
elif child_0_token == "q":
|
||||
while self._pos - beginning_pos < array_length:
|
||||
self._pos += -self._pos & 7 # align 8
|
||||
key = self._read_uint16_unpack()
|
||||
result_dict[key] = self._read_variant()
|
||||
if child_0_token in "os" and child_1_token == "v":
|
||||
while self._pos - beginning_pos < array_length:
|
||||
self._pos += -self._pos & 7 # align 8
|
||||
key = self._read_string_unpack()
|
||||
result_dict[key] = self._read_variant()
|
||||
elif child_0_token == "q" and child_1_token == "v":
|
||||
while self._pos - beginning_pos < array_length:
|
||||
self._pos += -self._pos & 7 # align 8
|
||||
key = self._read_uint16_unpack()
|
||||
result_dict[key] = self._read_variant()
|
||||
elif child_0_token == "s" and child_1_token == "a":
|
||||
while self._pos - beginning_pos < array_length:
|
||||
self._pos += -self._pos & 7 # align 8
|
||||
key = self._read_string_unpack()
|
||||
result_dict[key] = self._read_array(child_1)
|
||||
else:
|
||||
reader_1 = self._readers[child_1_token]
|
||||
reader_0 = self._readers[child_0_token]
|
||||
|
||||
while self._pos - beginning_pos < array_length:
|
||||
self._pos += -self._pos & 7 # align 8
|
||||
key = reader_0(self, child_0)
|
||||
@ -528,6 +562,12 @@ class Unmarshaller:
|
||||
self._read_array(SIGNATURE_TREE_SA_SV_AS_TYPES_1),
|
||||
self._read_array(SIGNATURE_TREE_SA_SV_AS_TYPES_2),
|
||||
]
|
||||
elif signature == "oa{sa{sv}}":
|
||||
tree = SIGNATURE_TREE_OA_SA_SV
|
||||
body = [
|
||||
self._read_string_unpack(),
|
||||
self._read_array(SIGNATURE_TREE_OA_SA_SV_TYPES_1),
|
||||
]
|
||||
else:
|
||||
tree = get_signature_tree(signature)
|
||||
body = [self._readers[t.token](self, t) for t in tree.types]
|
||||
|
||||
@ -228,6 +228,99 @@ def test_unmarshall_bluez_message():
|
||||
]
|
||||
|
||||
|
||||
def test_unmarshall_bluez_interfaces_added_message():
|
||||
bluez_interfaces_added_message = (
|
||||
b'l\4\1\1\240\2\0\0\227\272\23\0u\0\0\0\1\1o\0\1\0\0\0/\0\0\0\0\0\0\0\2\1s\0"\0\0\0'
|
||||
b"org.freedesktop.DBus.ObjectManager\0\0\0\0\0\0\3\1s\0\17\0\0\0InterfacesAdded\0\10"
|
||||
b"\1g\0\noa{sa{sv}}\0\7\1s\0\4\0\0\0:1.4\0\0\0\0%\0\0\0/org/bluez/hci1/dev_58_2D_34"
|
||||
b"_60_26_36\0\0\0p\2\0\0#\0\0\0org.freedesktop.DBus.Introspectable\0\0\0\0\0\0\0\0\0"
|
||||
b"\21\0\0\0org.bluez.Device1\0\0\0\364\1\0\0\0\0\0\0\7\0\0\0Address\0\1s\0\0\21\0\0"
|
||||
b"\00058:2D:34:60:26:36\0\0\0\v\0\0\0AddressType\0\1s\0\0\6\0\0\0public\0\0\4\0\0\0"
|
||||
b"Name\0\1s\0\33\0\0\0Qingping Door/Window Sensor\0\0\0\0\0\5\0\0\0Alias\0\1s\0\0\0"
|
||||
b"\0\33\0\0\0Qingping Door/Window Sensor\0\6\0\0\0Paired\0\1b\0\0\0\0\0\0\0\0\0\0\0"
|
||||
b"\7\0\0\0Trusted\0\1b\0\0\0\0\0\0\0\0\0\0\7\0\0\0Blocked\0\1b\0\0\0\0\0\0\0\0\0\0\r"
|
||||
b"\0\0\0LegacyPairing\0\1b\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0RSSI\0\1n\0\316\377\0\0\t"
|
||||
b"\0\0\0Connected\0\1b\0\0\0\0\0\0\0\0\5\0\0\0UUIDs\0\2as\0\0\0\0\0\0\0\0\0\0\0\7\0"
|
||||
b"\0\0Adapter\0\1o\0\0\17\0\0\0/org/bluez/hci1\0\0\0\0\0\v\0\0\0ServiceData\0\5a{sv}"
|
||||
b"\0\0@\0\0\0\0\0\0\0$\0\0\0000000fe95-0000-1000-8000-00805f9b34fb\0\2ay\0\0\0\0\f\0"
|
||||
b"\0\0000X\326\3\0026&`4-X\10\20\0\0\0ServicesResolved\0\1b\0\0\0\0\0\0\0\0\0\37\0\0"
|
||||
b"\0org.freedesktop.DBus.Properties\0\0\0\0\0"
|
||||
)
|
||||
|
||||
stream = io.BytesIO(bluez_interfaces_added_message)
|
||||
unmarshaller = Unmarshaller(stream)
|
||||
assert unmarshaller.unmarshall()
|
||||
message = unmarshaller.message
|
||||
assert message is not None
|
||||
assert message.body == [
|
||||
"/org/bluez/hci1/dev_58_2D_34_60_26_36",
|
||||
{
|
||||
"org.bluez.Device1": {
|
||||
"Adapter": Variant("o", "/org/bluez/hci1"),
|
||||
"Address": Variant("s", "58:2D:34:60:26:36"),
|
||||
"AddressType": Variant("s", "public"),
|
||||
"Alias": Variant("s", "Qingping Door/Window Sensor"),
|
||||
"Blocked": Variant("b", False),
|
||||
"Connected": Variant("b", False),
|
||||
"LegacyPairing": Variant("b", False),
|
||||
"Name": Variant("s", "Qingping Door/Window Sensor"),
|
||||
"Paired": Variant("b", False),
|
||||
"RSSI": Variant("n", -50),
|
||||
"ServiceData": Variant(
|
||||
"a{sv}",
|
||||
{
|
||||
"0000fe95-0000-1000-8000-00805f9b34fb": Variant(
|
||||
"ay", bytearray(b"0X\xd6\x03\x026&`4-X\x08")
|
||||
)
|
||||
},
|
||||
),
|
||||
"ServicesResolved": Variant("b", False),
|
||||
"Trusted": Variant("b", False),
|
||||
"UUIDs": Variant("as", []),
|
||||
},
|
||||
"org.freedesktop.DBus.Introspectable": {},
|
||||
"org.freedesktop.DBus.Properties": {},
|
||||
},
|
||||
]
|
||||
assert message.sender == ":1.4"
|
||||
assert message.path == "/"
|
||||
assert message.interface == "org.freedesktop.DBus.ObjectManager"
|
||||
assert message.member == "InterfacesAdded"
|
||||
assert message.signature == "oa{sa{sv}}"
|
||||
assert message.message_type == MessageType.SIGNAL
|
||||
assert message.flags == MessageFlag.NO_REPLY_EXPECTED
|
||||
assert message.serial == 1292951
|
||||
assert message.destination is None
|
||||
unpacked = unpack_variants(message.body)
|
||||
assert unpacked == [
|
||||
"/org/bluez/hci1/dev_58_2D_34_60_26_36",
|
||||
{
|
||||
"org.bluez.Device1": {
|
||||
"Adapter": "/org/bluez/hci1",
|
||||
"Address": "58:2D:34:60:26:36",
|
||||
"AddressType": "public",
|
||||
"Alias": "Qingping Door/Window Sensor",
|
||||
"Blocked": False,
|
||||
"Connected": False,
|
||||
"LegacyPairing": False,
|
||||
"Name": "Qingping Door/Window Sensor",
|
||||
"Paired": False,
|
||||
"RSSI": -50,
|
||||
"ServiceData": {
|
||||
"0000fe95-0000-1000-8000-00805f9b34fb": bytearray(
|
||||
b"0X\xd6\x03" b"\x026&`" b"4-X\x08"
|
||||
)
|
||||
},
|
||||
"ServicesResolved": False,
|
||||
"Trusted": False,
|
||||
"UUIDs": [],
|
||||
},
|
||||
"org.freedesktop.DBus.Introspectable": {},
|
||||
"org.freedesktop.DBus.Properties": {},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def test_ay_buffer():
|
||||
body = [bytes(10000)]
|
||||
msg = Message(path="/test", member="test", signature="ay", body=body)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user