Faster swap.

Arena never changes, so no need to swap it.

Also explicitly instantiated memswap template to reduce code size.

```
name                              old INSTRUCTIONS/op     new INSTRUCTIONS/op     delta
BM_ProtoSwap<TestAllTypes>           356 ± 0%                300 ± 0%  -15.73%      (p=0.000 n=100+100)
BM_ProtoSwap<NestedTestAllTypes>    67.0 ± 0%               63.0 ± 0%   -5.97%      (p=0.000 n=100+100)
BM_ProtoSwap<ForeignMessage>        31.0 ± 0%               31.0 ± 0%     ~     (all samples are equal)
BM_ProtoSwap<TestAllExtensions>     52.0 ± 0%               52.0 ± 0%     ~     (all samples are equal)
```

PiperOrigin-RevId: 567379442
pull/14169/head
Protobuf Team Bot 1 year ago committed by Copybara-Service
parent 9b46ed520e
commit bfbc95d41e
  1. 4
      src/google/protobuf/repeated_ptr_field.cc
  2. 38
      src/google/protobuf/repeated_ptr_field.h

@ -147,6 +147,10 @@ void InternalOutOfLineDeleteMessageLite(MessageLite* message) {
delete message; delete message;
} }
template PROTOBUF_EXPORT_TEMPLATE_DEFINE void
memswap<ArenaOffsetHelper<RepeatedPtrFieldBase>::value>(
char* PROTOBUF_RESTRICT, char* PROTOBUF_RESTRICT);
} // namespace internal } // namespace internal
} // namespace protobuf } // namespace protobuf

@ -127,6 +127,14 @@ struct IsMovable
: std::integral_constant<bool, std::is_move_constructible<T>::value && : std::integral_constant<bool, std::is_move_constructible<T>::value &&
std::is_move_assignable<T>::value> {}; std::is_move_assignable<T>::value> {};
// A trait that tells offset of `T::arena_`.
//
// Do not use this struct - it exists for internal use only.
template <typename T>
struct ArenaOffsetHelper {
constexpr static size_t value = offsetof(T, arena_);
};
// This is the common base class for RepeatedPtrFields. It deals only in void* // This is the common base class for RepeatedPtrFields. It deals only in void*
// pointers. Users should not use this interface directly. // pointers. Users should not use this interface directly.
// //
@ -160,15 +168,15 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
internal::GenericTypeHandler<MessageLite>, Handler>::type; internal::GenericTypeHandler<MessageLite>, Handler>::type;
constexpr RepeatedPtrFieldBase() constexpr RepeatedPtrFieldBase()
: arena_(nullptr), : tagged_rep_or_elem_(nullptr),
current_size_(0), current_size_(0),
total_size_(kSSOCapacity), total_size_(kSSOCapacity),
tagged_rep_or_elem_(nullptr) {} arena_(nullptr) {}
explicit RepeatedPtrFieldBase(Arena* arena) explicit RepeatedPtrFieldBase(Arena* arena)
: arena_(arena), : tagged_rep_or_elem_(nullptr),
current_size_(0), current_size_(0),
total_size_(kSSOCapacity), total_size_(kSSOCapacity),
tagged_rep_or_elem_(nullptr) {} arena_(arena) {}
RepeatedPtrFieldBase(const RepeatedPtrFieldBase&) = delete; RepeatedPtrFieldBase(const RepeatedPtrFieldBase&) = delete;
RepeatedPtrFieldBase& operator=(const RepeatedPtrFieldBase&) = delete; RepeatedPtrFieldBase& operator=(const RepeatedPtrFieldBase&) = delete;
@ -305,8 +313,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
inline void InternalSwap(RepeatedPtrFieldBase* PROTOBUF_RESTRICT rhs) { inline void InternalSwap(RepeatedPtrFieldBase* PROTOBUF_RESTRICT rhs) {
ABSL_DCHECK(this != rhs); ABSL_DCHECK(this != rhs);
// Swap all fields at once. // Swap all fields except arena pointer at once.
internal::memswap<sizeof(RepeatedPtrFieldBase)>( internal::memswap<ArenaOffsetHelper<RepeatedPtrFieldBase>::value>(
reinterpret_cast<char*>(this), reinterpret_cast<char*>(rhs)); reinterpret_cast<char*>(this), reinterpret_cast<char*>(rhs));
} }
@ -664,6 +672,11 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
friend class internal::TcParser; // TODO: Remove this friend. friend class internal::TcParser; // TODO: Remove this friend.
// Expose offset of `arena_` without exposing the member itself.
// Used to optimize code size of `InternalSwap` method.
template <typename T>
friend struct ArenaOffsetHelper;
// The reflection implementation needs to call protected methods directly, // The reflection implementation needs to call protected methods directly,
// reinterpreting pointers as being to Message instead of a specific Message // reinterpreting pointers as being to Message instead of a specific Message
// subclass. // subclass.
@ -824,10 +837,10 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// misses due to the indirection, because these fields are checked frequently. // misses due to the indirection, because these fields are checked frequently.
// Placing all fields directly in the RepeatedPtrFieldBase instance would cost // Placing all fields directly in the RepeatedPtrFieldBase instance would cost
// significant performance for memory-sensitive workloads. // significant performance for memory-sensitive workloads.
Arena* arena_; void* tagged_rep_or_elem_;
int current_size_; int current_size_;
int total_size_; int total_size_;
void* tagged_rep_or_elem_; Arena* arena_;
}; };
void InternalOutOfLineDeleteMessageLite(MessageLite* message); void InternalOutOfLineDeleteMessageLite(MessageLite* message);
@ -2136,6 +2149,15 @@ UnsafeArenaAllocatedRepeatedPtrFieldBackInserter(
mutable_field); mutable_field);
} }
namespace internal {
// Size optimization for `memswap<N>` - supplied below N is used by every
// `RepeatedPtrField<T>`.
extern template PROTOBUF_EXPORT_TEMPLATE_DECLARE void
memswap<ArenaOffsetHelper<RepeatedPtrFieldBase>::value>(
char* PROTOBUF_RESTRICT, char* PROTOBUF_RESTRICT);
} // namespace internal
} // namespace protobuf } // namespace protobuf
} // namespace google } // namespace google

Loading…
Cancel
Save