From 454802da379b3b6ffc881045fb21d865c55aa2fe Mon Sep 17 00:00:00 2001 From: saipubw Date: Tue, 28 Mar 2023 15:37:09 +0800 Subject: [PATCH] [struct_pack] limit force inline (#254) * [struct_pack] avoid excess optimize in benchmark. * [struct_pack] Limit force inline when STRUCT_PACK_OPTIMIZE no defined * fix --- include/struct_pack/struct_pack.hpp | 2 +- include/struct_pack/struct_pack/reflection.h | 6 + .../struct_pack/struct_pack_impl.hpp | 279 +++++++++--------- src/struct_pack/benchmark/msgpack_sample.hpp | 2 + src/struct_pack/benchmark/no_op.cpp | 4 +- src/struct_pack/benchmark/no_op.h | 3 +- src/struct_pack/benchmark/protobuf_sample.hpp | 3 + .../benchmark/struct_pack_sample.hpp | 2 + .../benchmark/struct_pb_sample.hpp | 3 + 9 files changed, 161 insertions(+), 143 deletions(-) diff --git a/include/struct_pack/struct_pack.hpp b/include/struct_pack/struct_pack.hpp index d3ff1c0cd..5affcd7cc 100644 --- a/include/struct_pack/struct_pack.hpp +++ b/include/struct_pack/struct_pack.hpp @@ -113,7 +113,7 @@ using unexpected = tl::unexpected; using unexpect_t = tl::unexpect_t; #endif -inline std::error_code make_error_code(struct_pack::errc err) { +STRUCT_PACK_INLINE std::error_code make_error_code(struct_pack::errc err) { return std::error_code(static_cast(err), struct_pack::detail::category()); } diff --git a/include/struct_pack/struct_pack/reflection.h b/include/struct_pack/struct_pack/reflection.h index ebae1a06b..693b4c124 100644 --- a/include/struct_pack/struct_pack/reflection.h +++ b/include/struct_pack/struct_pack/reflection.h @@ -40,6 +40,12 @@ #define CONSTEXPR_INLINE_LAMBDA constexpr __attribute__((always_inline)) #endif +#if defined STRUCT_PACK_OPTIMIZE +#define STRUCT_PACK_MAY_INLINE STRUCT_PACK_INLINE +#else +#define STRUCT_PACK_MAY_INLINE inline +#endif + namespace struct_pack { template diff --git a/include/struct_pack/struct_pack/struct_pack_impl.hpp b/include/struct_pack/struct_pack/struct_pack_impl.hpp index 6104d7bf3..ffca6ecde 100644 --- a/include/struct_pack/struct_pack/struct_pack_impl.hpp +++ b/include/struct_pack/struct_pack/struct_pack_impl.hpp @@ -1711,9 +1711,9 @@ class packer { template -STRUCT_PACK_INLINE void serialize_to(Writer &writer, - const serialize_buffer_size &info, - const Args &...args) { +STRUCT_PACK_MAY_INLINE void serialize_to(Writer &writer, + const serialize_buffer_size &info, + const Args &...args) { static_assert(sizeof...(args) > 0); detail::packer> o(writer, info); switch ((info.metainfo() & 0b11000) >> 3) { @@ -1792,139 +1792,8 @@ class unpacker { STRUCT_PACK_INLINE unpacker(Reader &reader) : reader_(reader) {} - template - STRUCT_PACK_INLINE struct_pack::errc deserialize_compatibles( - T &t, Args &...args, std::index_sequence) { - using Type = get_args_type; - struct_pack::errc err_code; - switch (size_type_) { - case 0: - ([&] { - err_code = deserialize_many<1, compatible_version_number[I]>( - t, args...); - return err_code == errc::ok; - }() && - ...); - break; -#ifdef STRUCT_PACK_OPTIMIZE - case 1: - ([&] { - err_code = deserialize_many<2, compatible_version_number[I]>( - t, args...); - return err_code == errc::ok; - }() && - ...); - break; - case 2: - ([&] { - err_code = deserialize_many<4, compatible_version_number[I]>( - t, args...); - return err_code == errc::ok; - }() && - ...); - break; - case 3: - ([&] { - err_code = deserialize_many<8, compatible_version_number[I]>( - t, args...); - return err_code == errc::ok; - }() && - ...); - break; -#else - case 1: - case 2: - case 3: - ([&] { - err_code = deserialize_many<2, compatible_version_number[I]>( - t, args...); - return err_code == errc::ok; - }() && - ...); - break; -#endif - default: - unreachable(); - } - if (size_type_ == - UCHAR_MAX) { // reuse size_type_ as a tag that the buffer miss some - // compatible field, whic is legal. - err_code = {}; - } - return err_code; - } - - template - STRUCT_PACK_INLINE struct_pack::errc deserialize_compatible_fields( - std::tuple_element_t())> &field, - std::index_sequence) { - using T = std::remove_cvref_t; - using Type = get_args_type; - struct_pack::errc err_code; - switch (size_type_) { - case 0: - ([&] { - err_code = - get_field_impl<1, compatible_version_number[Is], U, I>( - field); - return err_code == errc::ok; - }() && - ...); - break; -#ifdef STRUCT_PACK_OPTIMIZE - case 1: - ([&] { - err_code = - get_field_impl<2, compatible_version_number[Is], U, I>( - field); - return err_code == errc::ok; - }() && - ...); - break; - case 2: - ([&] { - err_code = - get_field_impl<4, compatible_version_number[Is], U, I>( - field); - return err_code == errc::ok; - }() && - ...); - break; - case 3: - ([&] { - err_code = - get_field_impl<8, compatible_version_number[Is], U, I>( - field); - return err_code == errc::ok; - }() && - ...); - break; -#else - case 1: - case 2: - case 3: - ([&] { - err_code = - get_field_impl<2, compatible_version_number[Is], U, I>( - field); - return err_code == errc::ok; - }() && - ...); - break; -#endif - default: - unreachable(); - } - if (size_type_ == - UCHAR_MAX) { // reuse size_type_ as a tag that the buffer miss some - // compatible field, whic is legal. - err_code = {}; - } - return err_code; - } - template - STRUCT_PACK_INLINE struct_pack::errc deserialize(T &t, Args &...args) { + STRUCT_PACK_MAY_INLINE struct_pack::errc deserialize(T &t, Args &...args) { using Type = get_args_type; constexpr bool has_compatible = check_if_compatible_element_exist())>(); @@ -1974,9 +1843,8 @@ class unpacker { } template - STRUCT_PACK_INLINE struct_pack::errc deserialize_with_len(std::size_t &len, - T &t, - Args &...args) { + STRUCT_PACK_MAY_INLINE struct_pack::errc deserialize_with_len( + std::size_t &len, T &t, Args &...args) { using Type = get_args_type; constexpr bool has_compatible = check_if_compatible_element_exist())>(); @@ -2027,7 +1895,7 @@ class unpacker { } template - STRUCT_PACK_INLINE struct_pack::errc get_field( + STRUCT_PACK_MAY_INLINE struct_pack::errc get_field( std::tuple_element_t())> &field) { using T = std::remove_cvref_t; using Type = get_args_type; @@ -2080,6 +1948,138 @@ class unpacker { return err_code; } + private: + template + STRUCT_PACK_INLINE struct_pack::errc deserialize_compatibles( + T &t, Args &...args, std::index_sequence) { + using Type = get_args_type; + struct_pack::errc err_code; + switch (size_type_) { + case 0: + ([&] { + err_code = deserialize_many<1, compatible_version_number[I]>( + t, args...); + return err_code == errc::ok; + }() && + ...); + break; +#ifdef STRUCT_PACK_OPTIMIZE + case 1: + ([&] { + err_code = deserialize_many<2, compatible_version_number[I]>( + t, args...); + return err_code == errc::ok; + }() && + ...); + break; + case 2: + ([&] { + err_code = deserialize_many<4, compatible_version_number[I]>( + t, args...); + return err_code == errc::ok; + }() && + ...); + break; + case 3: + ([&] { + err_code = deserialize_many<8, compatible_version_number[I]>( + t, args...); + return err_code == errc::ok; + }() && + ...); + break; +#else + case 1: + case 2: + case 3: + ([&] { + err_code = deserialize_many<2, compatible_version_number[I]>( + t, args...); + return err_code == errc::ok; + }() && + ...); + break; +#endif + default: + unreachable(); + } + if (size_type_ == + UCHAR_MAX) { // reuse size_type_ as a tag that the buffer miss some + // compatible field, whic is legal. + err_code = {}; + } + return err_code; + } + + template + STRUCT_PACK_INLINE struct_pack::errc deserialize_compatible_fields( + std::tuple_element_t())> &field, + std::index_sequence) { + using T = std::remove_cvref_t; + using Type = get_args_type; + struct_pack::errc err_code; + switch (size_type_) { + case 0: + ([&] { + err_code = + get_field_impl<1, compatible_version_number[Is], U, I>( + field); + return err_code == errc::ok; + }() && + ...); + break; +#ifdef STRUCT_PACK_OPTIMIZE + case 1: + ([&] { + err_code = + get_field_impl<2, compatible_version_number[Is], U, I>( + field); + return err_code == errc::ok; + }() && + ...); + break; + case 2: + ([&] { + err_code = + get_field_impl<4, compatible_version_number[Is], U, I>( + field); + return err_code == errc::ok; + }() && + ...); + break; + case 3: + ([&] { + err_code = + get_field_impl<8, compatible_version_number[Is], U, I>( + field); + return err_code == errc::ok; + }() && + ...); + break; +#else + case 1: + case 2: + case 3: + ([&] { + err_code = + get_field_impl<2, compatible_version_number[Is], U, I>( + field); + return err_code == errc::ok; + }() && + ...); + break; +#endif + default: + unreachable(); + } + if (size_type_ == + UCHAR_MAX) { // reuse size_type_ as a tag that the buffer miss some + // compatible field, whic is legal. + err_code = {}; + } + return err_code; + } + template STRUCT_PACK_INLINE struct_pack::errc get_field_impl( std::tuple_element_t())> &field) { @@ -2108,7 +2108,6 @@ class unpacker { return err_code; } - private: template struct variant_construct_helper { diff --git a/src/struct_pack/benchmark/msgpack_sample.hpp b/src/struct_pack/benchmark/msgpack_sample.hpp index cc02a2278..2ebffe2ba 100644 --- a/src/struct_pack/benchmark/msgpack_sample.hpp +++ b/src/struct_pack/benchmark/msgpack_sample.hpp @@ -59,6 +59,7 @@ struct message_pack_sample : public base_sample { for (int i = 0; i < ITERATIONS; ++i) { buffer_.clear(); msgpack::pack(buffer_, sample); + no_op(buffer_.data()); } } ser_time_elapsed_map_.emplace(sample_type, ns); @@ -86,6 +87,7 @@ struct message_pack_sample : public base_sample { msgpack::unpack(vec[i], buffer_.data(), buffer_.size()); vec[i].get().as(); } + no_op((char *)vec.data()); } deser_time_elapsed_map_.emplace(sample_type, ns); } diff --git a/src/struct_pack/benchmark/no_op.cpp b/src/struct_pack/benchmark/no_op.cpp index d4af5f382..635012442 100644 --- a/src/struct_pack/benchmark/no_op.cpp +++ b/src/struct_pack/benchmark/no_op.cpp @@ -1,3 +1,5 @@ #include "no_op.h" -void no_op(std::vector* monsters) {} \ No newline at end of file +void no_op(std::string& str) {} + +void no_op(char* data) {} \ No newline at end of file diff --git a/src/struct_pack/benchmark/no_op.h b/src/struct_pack/benchmark/no_op.h index 9fc30f3fa..e9cc3d064 100644 --- a/src/struct_pack/benchmark/no_op.h +++ b/src/struct_pack/benchmark/no_op.h @@ -1,4 +1,5 @@ #pragma once #include "data_def.hpp" -void no_op(std::vector* monsters = nullptr); \ No newline at end of file +void no_op(std::string& str); +void no_op(char* data); \ No newline at end of file diff --git a/src/struct_pack/benchmark/protobuf_sample.hpp b/src/struct_pack/benchmark/protobuf_sample.hpp index 97cd6fbb2..5ade006e9 100644 --- a/src/struct_pack/benchmark/protobuf_sample.hpp +++ b/src/struct_pack/benchmark/protobuf_sample.hpp @@ -17,6 +17,7 @@ #include "ScopedTimer.hpp" #include "benchmark.pb.h" #include "config.hpp" +#include "no_op.h" #include "sample.hpp" namespace protobuf_sample { auto create_rects(size_t object_count) { @@ -180,6 +181,7 @@ struct protobuf_sample_t : public base_sample { for (int i = 0; i < ITERATIONS; ++i) { buffer_.clear(); sample.SerializeToString(&buffer_); + no_op(buffer_); } } ser_time_elapsed_map_.emplace(sample_type, ns); @@ -206,6 +208,7 @@ struct protobuf_sample_t : public base_sample { for (int i = 0; i < ITERATIONS; ++i) { vec[i].ParseFromString(buffer_); } + no_op((char *)vec.data()); } deser_time_elapsed_map_.emplace(sample_type, ns); } diff --git a/src/struct_pack/benchmark/struct_pack_sample.hpp b/src/struct_pack/benchmark/struct_pack_sample.hpp index 4aea4a774..3ffa220ba 100644 --- a/src/struct_pack/benchmark/struct_pack_sample.hpp +++ b/src/struct_pack/benchmark/struct_pack_sample.hpp @@ -87,6 +87,7 @@ struct struct_pack_sample : public base_sample { for (int i = 0; i < ITERATIONS; ++i) { buffer_.clear(); struct_pack::serialize_to(buffer_, sample); + no_op(buffer_); } } ser_time_elapsed_map_.emplace(sample_type, ns); @@ -113,6 +114,7 @@ struct struct_pack_sample : public base_sample { for (int i = 0; i < ITERATIONS; ++i) { [[maybe_unused]] auto ec = struct_pack::deserialize_to(vec[i], buffer_); } + no_op((char *)vec.data()); } deser_time_elapsed_map_.emplace(sample_type, ns); } diff --git a/src/struct_pack/benchmark/struct_pb_sample.hpp b/src/struct_pack/benchmark/struct_pb_sample.hpp index b510060a0..6160cdc10 100644 --- a/src/struct_pack/benchmark/struct_pb_sample.hpp +++ b/src/struct_pack/benchmark/struct_pb_sample.hpp @@ -6,6 +6,7 @@ #include "ScopedTimer.hpp" #include "benchmark.struct_pb.h" +#include "no_op.h" #include "sample.hpp" namespace struct_pb_sample { @@ -114,6 +115,7 @@ struct struct_pb_sample_t : public base_sample { buffer_.resize(sz); struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(), sample); + no_op(buffer_); } } @@ -142,6 +144,7 @@ struct struct_pb_sample_t : public base_sample { vec[i], buffer_.data(), buffer_.size()); assert(ok); } + no_op((char*)vec.data()); } deser_time_elapsed_map_.emplace(sample_type, ns);