From b9ccaecd461acbe2016c74379973137c875209d8 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Mon, 5 Oct 2020 09:48:36 +0200 Subject: [PATCH 1/2] unmarshaller: optimize alignment padding formula Avoid using the slow MOD (%) operator. Use bitvise AND (&) instead. Signed-off-by: Robin Jarry --- dbus_next/_private/unmarshaller.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index 638bcc2..eaa9bfe 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -71,11 +71,30 @@ def read(self, n, prefetch=False): self.offset += n return prev + @staticmethod + def _padding(offset, align): + """ + Get padding bytes to get to the next align bytes mark. + + For any align value, the correct padding formula is: + + (align - (offset % align)) % align + + However, if align is a power of 2 (always the case here), the slow MOD + operator can be replaced by a bitwise AND: + + (align - (offset & (align - 1))) & (align - 1) + + Which can be simplified to: + + (-offset) & (align - 1) + """ + return (-offset) & (align - 1) + def align(self, n): - padding = n - self.offset % n - if padding == 0 or padding == n: - return - self.read(padding) + padding = self._padding(self.offset, n) + if padding > 0: + self.read(padding) def read_byte(self, _=None): return self.buf[self.read(1)] From cdfbb688693d3c1f81fcf9c2da33564e29da83a3 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Mon, 5 Oct 2020 09:43:41 +0200 Subject: [PATCH 2/2] unmarshaller: prefetch header alignment bytes When the message header is not a multiple of 8 bytes long, the alignment bytes will not be prefetched and an additional read() system call will be made when reading the end of the body. Add the padding bytes to the prefetch length. Fixes: 7efeef4f8f71 ("unmarshaller: reduce number of read system calls") Signed-off-by: Robin Jarry --- dbus_next/_private/unmarshaller.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index eaa9bfe..7f48a92 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -228,7 +228,8 @@ def _unmarshall(self): serial = self.read_uint32() header_len = self.read_uint32() - self.read(header_len + body_len, prefetch=True) + msg_len = header_len + self._padding(header_len, 8) + body_len + self.read(msg_len, prefetch=True) # backtrack offset since header array length needs to be read again self.offset -= 4