feat: optimize for interfaces added messages (#122)

This commit is contained in:
J. Nick Koston 2022-10-29 00:14:32 -05:00 committed by GitHub
parent 864843c9e5
commit c05a27aef9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 196 additions and 11 deletions

View 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")

View File

@ -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)

View File

@ -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]

View File

@ -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)