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 <dont inline bad cases>
  BigString: 222092ns
  ComplexLittleObjects: 34115ns
  ComplexLittleObjectsBig: 6222801ns

bitsery <original>
  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.
This commit is contained in:
Pol Marcet Sardà
2024-06-24 10:57:22 +02:00
committed by Mindaugas Vinkelis
parent cd73aca2f5
commit be2f295310
3 changed files with 82 additions and 10 deletions

View File

@@ -269,12 +269,11 @@ private:
void maybeResize(size_t newOffset, std::true_type)
{
if (newOffset > _bufferSize) {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(
*_buffer, _currOffset, newOffset);
_beginIt = std::begin(*_buffer);
_bufferSize = traits::ContainerTraits<Buffer>::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<diff_t>(_currOffset));
_currOffset = newOffset;
}
BITSERY_NOINLINE void doResize(size_t newOffset)
{
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(
*_buffer, _currOffset, newOffset);
_beginIt = std::begin(*_buffer);
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
}
};
}

View File

@@ -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"

View File

@@ -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<T, true>
static_cast<size_t>(static_cast<double>(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);
}
};