forked from Kistler-Group/sdbus-cpp
perf: optimize serialization of arrays of trivial D-Bus types (#340)
* Improve performance of std::vector<> per Issue #339. * refactor: improve performance of vector serialization --------- Co-authored-by: Plinio Andrade <plinio.andrade@oracle.com> Co-authored-by: Stanislav Angelovič <stanislav.angelovic@protonmail.com>
This commit is contained in:
146
include/sdbus-c++/Message.h
Normal file → Executable file
146
include/sdbus-c++/Message.h
Normal file → Executable file
@@ -85,6 +85,10 @@ namespace sdbus {
|
||||
Message& operator<<(const ObjectPath &item);
|
||||
Message& operator<<(const Signature &item);
|
||||
Message& operator<<(const UnixFd &item);
|
||||
template <typename _Element> Message& operator<<(const std::vector<_Element>& items);
|
||||
template <typename _Key, typename _Value> Message& operator<<(const std::map<_Key, _Value>& items);
|
||||
template <typename... _ValueTypes> Message& operator<<(const Struct<_ValueTypes...>& item);
|
||||
template <typename... _ValueTypes> 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 <typename _Element> Message& operator>>(std::vector<_Element>& items);
|
||||
template <typename _Key, typename _Value> Message& operator>>(std::map<_Key, _Value>& items);
|
||||
template <typename... _ValueTypes> Message& operator>>(Struct<_ValueTypes...>& item);
|
||||
template <typename... _ValueTypes> 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 <typename _Element>
|
||||
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 <typename _Key, typename _Value>
|
||||
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 <typename... _ValueTypes>
|
||||
inline Message& operator<<(Message& msg, const Struct<_ValueTypes...>& item)
|
||||
inline Message& Message::operator<<(const Struct<_ValueTypes...>& item)
|
||||
{
|
||||
auto structSignature = signature_of<Struct<_ValueTypes...>>::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 <typename... _ValueTypes>
|
||||
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 <typename _Element>
|
||||
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 <typename _Key, typename _Value>
|
||||
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 <typename... _ValueTypes>
|
||||
inline Message& operator>>(Message& msg, Struct<_ValueTypes...>& item)
|
||||
inline Message& Message::operator>>(Struct<_ValueTypes...>& item)
|
||||
{
|
||||
auto structSignature = signature_of<Struct<_ValueTypes...>>::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 <typename... _ValueTypes>
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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<void>
|
||||
{
|
||||
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<bool>
|
||||
{
|
||||
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<uint8_t>
|
||||
{
|
||||
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<int16_t>
|
||||
{
|
||||
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<uint16_t>
|
||||
{
|
||||
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<int32_t>
|
||||
{
|
||||
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<uint32_t>
|
||||
{
|
||||
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<int64_t>
|
||||
{
|
||||
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<uint64_t>
|
||||
{
|
||||
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<double>
|
||||
{
|
||||
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<char*>
|
||||
{
|
||||
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<const char*>
|
||||
{
|
||||
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<char[_N]>
|
||||
{
|
||||
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<const char[_N]>
|
||||
{
|
||||
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<std::string>
|
||||
{
|
||||
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<Struct<_ValueTypes...>>
|
||||
{
|
||||
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<Variant>
|
||||
{
|
||||
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<ObjectPath>
|
||||
{
|
||||
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<Signature>
|
||||
{
|
||||
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<UnixFd>
|
||||
{
|
||||
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<std::vector<_Element>>
|
||||
{
|
||||
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<std::map<_Key, _Value>>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
|
14
src/Message.cpp
Normal file → Executable file
14
src/Message.cpp
Normal file → Executable file
@@ -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);
|
||||
|
Reference in New Issue
Block a user