From 29c877a89acebe121db11aa870655fcc3ad6e978 Mon Sep 17 00:00:00 2001 From: pliniofpa Date: Thu, 27 Jul 2023 12:31:49 -0400 Subject: [PATCH] perf: optimize serialization of arrays of trivial D-Bus types (#340) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improve performance of std::vector<> per Issue #339. * refactor: improve performance of vector serialization --------- Co-authored-by: Plinio Andrade Co-authored-by: Stanislav Angelovič --- include/sdbus-c++/Message.h | 146 ++++++++++++++++++++------------- include/sdbus-c++/TypeTraits.h | 23 ++++++ src/Message.cpp | 14 ++++ 3 files changed, 127 insertions(+), 56 deletions(-) mode change 100644 => 100755 include/sdbus-c++/Message.h mode change 100644 => 100755 src/Message.cpp diff --git a/include/sdbus-c++/Message.h b/include/sdbus-c++/Message.h old mode 100644 new mode 100755 index b3ec368..742d4e3 --- a/include/sdbus-c++/Message.h +++ b/include/sdbus-c++/Message.h @@ -85,6 +85,10 @@ namespace sdbus { Message& operator<<(const ObjectPath &item); Message& operator<<(const Signature &item); Message& operator<<(const UnixFd &item); + template Message& operator<<(const std::vector<_Element>& items); + template Message& operator<<(const std::map<_Key, _Value>& items); + template Message& operator<<(const Struct<_ValueTypes...>& item); + template Message& operator<<(const std::tuple<_ValueTypes...>& item); Message& operator>>(bool& item); Message& operator>>(int16_t& item); @@ -101,6 +105,10 @@ namespace sdbus { Message& operator>>(ObjectPath &item); Message& operator>>(Signature &item); Message& operator>>(UnixFd &item); + template Message& operator>>(std::vector<_Element>& items); + template Message& operator>>(std::map<_Key, _Value>& items); + template Message& operator>>(Struct<_ValueTypes...>& item); + template Message& operator>>(std::tuple<_ValueTypes...>& item); Message& openContainer(const std::string& signature); Message& closeContainer(); @@ -146,6 +154,10 @@ namespace sdbus { class Factory; + private: + void appendArray(char type, const void *ptr, size_t size); + void readArray(char type, const void **ptr, size_t *size); + protected: Message() = default; explicit Message(internal::ISdBus* sdbus) noexcept; @@ -245,37 +257,46 @@ namespace sdbus { }; template - inline Message& operator<<(Message& msg, const std::vector<_Element>& items) + inline Message& Message::operator<<(const std::vector<_Element>& items) { - msg.openContainer(signature_of<_Element>::str()); + // Use faster, one-step serialization of contiguous array of elements of trivial D-Bus types except bool, + // otherwise use step-by-step serialization of individual elements. + if constexpr (signature_of<_Element>::is_trivial_dbus_type && !std::is_same_v<_Element, bool>) + { + appendArray(*signature_of<_Element>::str().c_str(), items.data(), items.size() * sizeof(_Element)); + } + else + { + openContainer(signature_of<_Element>::str()); - for (const auto& item : items) - msg << item; + for (const auto& item : items) + *this << item; - msg.closeContainer(); + closeContainer(); + } - return msg; + return *this; } template - inline Message& operator<<(Message& msg, const std::map<_Key, _Value>& items) + inline Message& Message::operator<<(const std::map<_Key, _Value>& items) { const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str(); const std::string arraySignature = "{" + dictEntrySignature + "}"; - msg.openContainer(arraySignature); + openContainer(arraySignature); for (const auto& item : items) { - msg.openDictEntry(dictEntrySignature); - msg << item.first; - msg << item.second; - msg.closeDictEntry(); + openDictEntry(dictEntrySignature); + *this << item.first; + *this << item.second; + closeDictEntry(); } - msg.closeContainer(); + closeContainer(); - return msg; + return *this; } namespace detail @@ -296,78 +317,91 @@ namespace sdbus { } template - inline Message& operator<<(Message& msg, const Struct<_ValueTypes...>& item) + inline Message& Message::operator<<(const Struct<_ValueTypes...>& item) { auto structSignature = signature_of>::str(); assert(structSignature.size() > 2); // Remove opening and closing parenthesis from the struct signature to get contents signature auto structContentSignature = structSignature.substr(1, structSignature.size()-2); - msg.openStruct(structContentSignature); - detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{}); - msg.closeStruct(); + openStruct(structContentSignature); + detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{}); + closeStruct(); - return msg; + return *this; } template - inline Message& operator<<(Message& msg, const std::tuple<_ValueTypes...>& item) + inline Message& Message::operator<<(const std::tuple<_ValueTypes...>& item) { - detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{}); - return msg; + detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{}); + return *this; } - template - inline Message& operator>>(Message& msg, std::vector<_Element>& items) + inline Message& Message::operator>>(std::vector<_Element>& items) { - if(!msg.enterContainer(signature_of<_Element>::str())) - return msg; - - while (true) + // Use faster, one-step deserialization of contiguous array of elements of trivial D-Bus types except bool, + // otherwise use step-by-step deserialization of individual elements. + if constexpr (signature_of<_Element>::is_trivial_dbus_type && !std::is_same_v<_Element, bool>) { - _Element elem; - if (msg >> elem) - items.emplace_back(std::move(elem)); - else - break; + size_t arraySize{}; + const _Element* arrayPtr{}; + + readArray(*signature_of<_Element>::str().c_str(), (const void**)&arrayPtr, &arraySize); + + items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(_Element))); + } + else + { + if(!enterContainer(signature_of<_Element>::str())) + return *this; + + while (true) + { + _Element elem; + if (*this >> elem) + items.emplace_back(std::move(elem)); + else + break; + } + + clearFlags(); + + exitContainer(); } - msg.clearFlags(); - - msg.exitContainer(); - - return msg; + return *this; } template - inline Message& operator>>(Message& msg, std::map<_Key, _Value>& items) + inline Message& Message::operator>>(std::map<_Key, _Value>& items) { const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str(); const std::string arraySignature = "{" + dictEntrySignature + "}"; - if (!msg.enterContainer(arraySignature)) - return msg; + if (!enterContainer(arraySignature)) + return *this; while (true) { - if (!msg.enterDictEntry(dictEntrySignature)) + if (!enterDictEntry(dictEntrySignature)) break; _Key key; _Value value; - msg >> key >> value; + *this >> key >> value; items.emplace(std::move(key), std::move(value)); - msg.exitDictEntry(); + exitDictEntry(); } - msg.clearFlags(); + clearFlags(); - msg.exitContainer(); + exitContainer(); - return msg; + return *this; } namespace detail @@ -388,27 +422,27 @@ namespace sdbus { } template - inline Message& operator>>(Message& msg, Struct<_ValueTypes...>& item) + inline Message& Message::operator>>(Struct<_ValueTypes...>& item) { auto structSignature = signature_of>::str(); // Remove opening and closing parenthesis from the struct signature to get contents signature auto structContentSignature = structSignature.substr(1, structSignature.size()-2); - if (!msg.enterStruct(structContentSignature)) - return msg; + if (!enterStruct(structContentSignature)) + return *this; - detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{}); + detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{}); - msg.exitStruct(); + exitStruct(); - return msg; + return *this; } template - inline Message& operator>>(Message& msg, std::tuple<_ValueTypes...>& item) + inline Message& Message::operator>>(std::tuple<_ValueTypes...>& item) { - detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{}); - return msg; + detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{}); + return *this; } } diff --git a/include/sdbus-c++/TypeTraits.h b/include/sdbus-c++/TypeTraits.h index 960d479..f322569 100644 --- a/include/sdbus-c++/TypeTraits.h +++ b/include/sdbus-c++/TypeTraits.h @@ -94,6 +94,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = false; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -108,6 +109,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -119,6 +121,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; static const std::string str() { @@ -130,6 +133,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; static const std::string str() { @@ -141,6 +145,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; static const std::string str() { @@ -152,6 +157,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; static const std::string str() { @@ -163,6 +169,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; static const std::string str() { @@ -174,6 +181,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; static const std::string str() { @@ -185,6 +193,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; static const std::string str() { @@ -196,6 +205,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; static const std::string str() { @@ -207,6 +217,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; static const std::string str() { @@ -218,6 +229,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -229,6 +241,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -240,6 +253,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -251,6 +265,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -262,6 +277,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -273,6 +289,7 @@ namespace sdbus { struct signature_of> { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -288,6 +305,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -299,6 +317,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -310,6 +329,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -321,6 +341,7 @@ namespace sdbus { struct signature_of { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -332,6 +353,7 @@ namespace sdbus { struct signature_of> { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { @@ -343,6 +365,7 @@ namespace sdbus { struct signature_of> { static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; static const std::string str() { diff --git a/src/Message.cpp b/src/Message.cpp old mode 100644 new mode 100755 index e0aec6f..2b2f735 --- a/src/Message.cpp +++ b/src/Message.cpp @@ -226,6 +226,11 @@ Message& Message::operator<<(const UnixFd &item) return *this; } +void Message::appendArray(char type, const void *ptr, size_t size) +{ + auto r = sd_bus_message_append_array((sd_bus_message*)msg_, type, ptr, size); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize an array", -r); +} Message& Message::operator>>(bool& item) { @@ -318,6 +323,15 @@ Message& Message::operator>>(uint64_t& item) return *this; } +void Message::readArray(char type, const void **ptr, size_t *size) +{ + auto r = sd_bus_message_read_array((sd_bus_message*)msg_, type, ptr, size); + if (r == 0) + ok_ = false; + + SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize an array", -r); +} + Message& Message::operator>>(double& item) { auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_DOUBLE, &item);