From be2f2953108c623cb21ebea1aee7ed7964ff3fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Marcet=20Sard=C3=A0?= Date: Mon, 24 Jun 2024 10:57:22 +0200 Subject: [PATCH] Discourage inlining the resize case, as that should happen rather rarely. If you additionally reuse buffers, this will increase the performance further. The metrics based on some internal benchmarks show a speedup of about 1%: bitsery BigString: 222092ns ComplexLittleObjects: 34115ns ComplexLittleObjectsBig: 6222801ns bitsery BigString: 242853ns ComplexLittleObjects: 35738ns ComplexLittleObjectsBig: 6334747ns The assembly has been checked to be correct: https://godbolt.org/z/Wr7qvfGrK Additionally, when allocating code, we can tell the compiler that we are not resizing to a lower size, this saves on gcc 14 a few instructions. The improvement should be negligible. --- include/bitsery/adapter/buffer.h | 19 +++++-- include/bitsery/bitsery.h | 65 +++++++++++++++++++++- include/bitsery/traits/core/std_defaults.h | 8 ++- 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/include/bitsery/adapter/buffer.h b/include/bitsery/adapter/buffer.h index c392f53..47a8678 100644 --- a/include/bitsery/adapter/buffer.h +++ b/include/bitsery/adapter/buffer.h @@ -269,12 +269,11 @@ private: void maybeResize(size_t newOffset, std::true_type) { - if (newOffset > _bufferSize) { - traits::BufferAdapterTraits::increaseBufferSize( - *_buffer, _currOffset, newOffset); - _beginIt = std::begin(*_buffer); - _bufferSize = traits::ContainerTraits::size(*_buffer); - } + if (newOffset > _bufferSize) + BITSERY_UNLIKELY + { + doResize(newOffset); + } } void maybeResize(BITSERY_MAYBE_UNUSED size_t newOffset, std::false_type) @@ -289,6 +288,14 @@ private: std::copy_n(data, size, _beginIt + static_cast(_currOffset)); _currOffset = newOffset; } + + BITSERY_NOINLINE void doResize(size_t newOffset) + { + traits::BufferAdapterTraits::increaseBufferSize( + *_buffer, _currOffset, newOffset); + _beginIt = std::begin(*_buffer); + _bufferSize = traits::ContainerTraits::size(*_buffer); + } }; } diff --git a/include/bitsery/bitsery.h b/include/bitsery/bitsery.h index 3d38bce..378b3ea 100644 --- a/include/bitsery/bitsery.h +++ b/include/bitsery/bitsery.h @@ -36,12 +36,73 @@ BITSERY_BUILD_VERSION_STR( \ BITSERY_MAJOR_VERSION, BITSERY_MINOR_VERSION, BITSERY_PATCH_VERSION) -#if __cplusplus > 201402L -#define BITSERY_MAYBE_UNUSED [[maybe_unused]] +#define BITSERY_DO_PRAGMA(x) _Pragma(#x) +#ifdef __GNUC__ +#define BITSERY_DISABLE_WARNINGS(...) \ + BITSERY_DO_PRAGMA(GCC diagnostic push) \ + BITSERY_DO_PRAGMA(GCC diagnostic ignored __VA_ARGS__) +#define BITSERY_ENABLE_WARNINGS() BITSERY_DO_PRAGMA(GCC diagnostic pop) +#elif defined(_MSC_VER) +#define BITSERY_DISABLE_WARNINGS(...) \ + BITSERY_DO_PRAGMA(GCC diagnostic push) \ + BITSERY_DO_PRAGMA(GCC diagnostic ignored __VA_ARGS__) \ + BITSERY_DO_PRAGMA(GCC diagnostic pop) +#define BITSERY_ENABLE_WARNINGS() BITSERY_DO_PRAGMA(GCC diagnostic pop) +#else +#define BITSERY_DISABLE_WARNINGS(...) +#define BITSERY_ENABLE_WARNINGS() +#endif + +#ifdef __clang__ +#define BITSERY_ATTRIBUTE(...) \ + BITSERY_DISABLE_WARNINGS("-Wfuture-attribute-extensions") \ + [[__VA_ARGS__]] BITSERY_ENABLE_WARNINGS() +#elif defined(__GNUC__) +#define BITSERY_ATTRIBUTE(...) [[__VA_ARGS__]] +#elif defined(_MSC_VER) +#define BITSERY_ATTRIBUTE(...) [[__VA_ARGS__]] +#else +#define BITSERY_ATTRIBUTE(...) [[__VA_ARGS__]] +#endif + +#if __has_cpp_attribute(likely) +#define BITSERY_LIKELY BITSERY_ATTRIBUTE(likey) +#else +#define BITSERY_LIKELY +#endif + +#if __has_cpp_attribute(unlikely) +#define BITSERY_UNLIKELY BITSERY_ATTRIBUTE(unlikely) +#else +#define BITSERY_UNLIKELY +#endif + +#if __has_cpp_attribute(maybe_unused) +#define BITSERY_MAYBE_UNUSED BITSERY_ATTRIBUTE(maybe_unused) #else #define BITSERY_MAYBE_UNUSED #endif +#if __GNUC__ +#define BITSERY_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) +#define BITSERY_NOINLINE __declspec(noinline) +#else +#define BITSERY_NOINLINE +#endif + +#if __GNUC__ +#define BITSERY_ASSUME(cond) \ + do { \ + if (!(cond)) \ + __builtin_unreachable(); \ + } while (0) +#elif defined(_MSC_VER) +#define BITSERY_ASSUME(cond) __assume(cond) +#else +#define BITSERY_ASSUME(cond) +#endif + #include "deserializer.h" #include "serializer.h" diff --git a/include/bitsery/traits/core/std_defaults.h b/include/bitsery/traits/core/std_defaults.h index 20cd5ef..748cdc3 100644 --- a/include/bitsery/traits/core/std_defaults.h +++ b/include/bitsery/traits/core/std_defaults.h @@ -23,6 +23,7 @@ #ifndef BITSERY_TRAITS_CORE_STD_DEFAULTS_H #define BITSERY_TRAITS_CORE_STD_DEFAULTS_H +#include "../../bitsery.h" #include "../../details/serialization_common.h" #include "traits.h" @@ -103,8 +104,11 @@ struct StdContainerForBufferAdapter static_cast(static_cast(container.size()) * 1.5) + 128; // make data cache friendly newSize -= newSize % 64; // 64 is cache line size - container.resize( - (std::max)(newSize > minSize ? newSize : minSize, container.capacity())); + auto resize = + (std::max)(newSize > minSize ? newSize : minSize, container.capacity()); + BITSERY_ASSUME(resize >= container.size()); + BITSERY_ASSUME(resize >= container.capacity()); + container.resize(resize); } };