Skip to content

Commit

Permalink
Allow NewStringElement inlining.
Browse files Browse the repository at this point in the history
```
name                                   old INSTRUCTIONS/op     new INSTRUCTIONS/op     delta
BM_RepeatedPtrField_Ctor                  251 ± 0%                251 ± 0%     ~     (all samples are equal)
BM_RepeatedPtrField_Add_Sso              84.8 ± 2%               76.7 ± 2%   -9.51%      (p=0.000 n=100+100)
BM_RepeatedPtrField_Add_FallbackToRep     215 ± 5%                199 ± 5%   -7.26%       (p=0.000 n=100+99)
BM_RepeatedPtrField_Add_Small             163 ± 1%                157 ± 1%   -3.96%      (p=0.000 n=100+100)
BM_RepeatedPtrField_Add_Large            96.7 ± 1%               90.7 ± 1%   -6.13%      (p=0.000 n=100+100)
BM_RepeatedPtrField_Add_HasCleared       36.5 ± 0%               36.5 ± 0%     ~           (p=0.314 n=76+79)
BM_RepeatedPtrField_AddAllocated         30.5 ± 0%               30.6 ± 1%     ~           (p=0.109 n=78+93)
BM_RepeatedPtrField_Sort                49.5k ± 0%              49.5k ± 0%   +0.12%        (p=0.000 n=80+95)
BM_RepeatedPtrField_SortIndirect          559 ± 0%                561 ± 6%     ~           (p=0.203 n=76+81)

```

PiperOrigin-RevId: 592241056
  • Loading branch information
protobuf-github-bot authored and copybara-github committed Dec 19, 2023
1 parent 8033709 commit 1427a85
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 21 deletions.
37 changes: 23 additions & 14 deletions src/google/protobuf/repeated_ptr_field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,41 +95,49 @@ void RepeatedPtrFieldBase::DestroyProtos() {
}

template <typename F>
auto* RepeatedPtrFieldBase::AddInternal(F factory) {
void* RepeatedPtrFieldBase::AddInternal(F factory) {
Arena* const arena = GetArena();
using Result = decltype(factory(arena));
absl::PrefetchToLocalCache(tagged_rep_or_elem_);
if (tagged_rep_or_elem_ == nullptr) {
ExchangeCurrentSize(1);
tagged_rep_or_elem_ = factory(arena);
return static_cast<Result>(tagged_rep_or_elem_);
return tagged_rep_or_elem_;
}
if (using_sso()) {
if (ExchangeCurrentSize(1) == 0) {
return static_cast<Result>(tagged_rep_or_elem_);
if (current_size_ == 0) {
ExchangeCurrentSize(1);
return tagged_rep_or_elem_;
}
} else {
absl::PrefetchToLocalCache(rep());
void*& result = *InternalExtend(1);
result = factory(arena);
Rep* r = rep();
r->allocated_size = 2;
ExchangeCurrentSize(2);
return result;
}
Rep* r = rep();
if (PROTOBUF_PREDICT_FALSE(SizeAtCapacity())) {
InternalExtend(1);
r = rep();
} else {
Rep* r = rep();
if (current_size_ != r->allocated_size) {
return static_cast<Result>(
r->elements[ExchangeCurrentSize(current_size_ + 1)]);
return r->elements[ExchangeCurrentSize(current_size_ + 1)];
}
}
Rep* r = rep();
++r->allocated_size;
void*& result = r->elements[ExchangeCurrentSize(current_size_ + 1)];
result = factory(arena);
return static_cast<Result>(result);
return result;
}

void* RepeatedPtrFieldBase::AddOutOfLineHelper(ElementFactory factory) {
void* RepeatedPtrFieldBase::AddMessageLite(ElementFactory factory) {
return AddInternal(factory);
}

void* RepeatedPtrFieldBase::AddString() {
return AddInternal([](Arena* arena) { return NewStringElement(arena); });
}

void RepeatedPtrFieldBase::CloseGap(int start, int num) {
if (using_sso()) {
if (start == 0 && num == 1) {
Expand All @@ -146,7 +154,8 @@ void RepeatedPtrFieldBase::CloseGap(int start, int num) {
}

MessageLite* RepeatedPtrFieldBase::AddMessage(const MessageLite* prototype) {
return AddInternal([prototype](Arena* a) { return prototype->New(a); });
return static_cast<MessageLite*>(
AddInternal([prototype](Arena* a) { return prototype->New(a); }));
}

void InternalOutOfLineDeleteMessageLite(MessageLite* message) {
Expand Down
17 changes: 10 additions & 7 deletions src/google/protobuf/repeated_ptr_field.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,10 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {

template <typename Handler>
Value<Handler>* Add() {
return cast<Handler>(AddOutOfLineHelper(Handler::GetNewFunc()));
if (std::is_same<Value<Handler>, std::string>{}) {
return cast<Handler>(AddString());
}
return cast<Handler>(AddMessageLite(Handler::GetNewFunc()));
}

template <
Expand Down Expand Up @@ -742,19 +745,19 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
return InternalExtend(n - Capacity());
}

// Internal helper for Add that keeps definition out-of-line.
void* AddOutOfLineHelper(ElementFactory factory);
// Internal helpers for Add that keep definition out-of-line.
void* AddMessageLite(ElementFactory factory);
void* AddString();

// Common implementation used by various Add* methods. `factory` is an object
// used to construct a new element unless there are spare cleared elements
// ready for reuse. Returns pointer to the new element.
//
// Note: avoid inlining this function in methods such as `Add()` as this would
// drastically increase binary size due to template instantiation and implicit
// inlining. Instead, use wrapper functions with out-of-line definition
// similar to `AddOutOfLineHelper`.
template <typename F>
auto* AddInternal(F factory);
// inlining.
template <typename Factory>
void* AddInternal(Factory factory);

// A few notes on internal representation:
//
Expand Down

0 comments on commit 1427a85

Please sign in to comment.