Skip to content

Commit 1f3fe2e

Browse files
ClaytonKnittelcopybara-github
authored andcommitted
Enable removed arena pointers from all fields.
This enables an optimization that removes the arena pointer from `RepeatedField`, `RepeatedPtrField`, `Map`, `ExtensionSet` (internal), and `StringPieceField` (internal). This change significantly reduces the size of Protobuf messages. It should also come with a decent speedup, since Protobuf will use less memory and `RepeatedField`s have been simplified. These fields still need to recover the arena when doing memory allocation (e.g. in `RepeatedField::Add`). In most places, when possible, the arena pointer is passed down from the containing message. However, this is not always possible, for example if you do something like `message->mutable_repeated_int32()->Add(10)`. These fields (with the exception of `ExtensionSet`) now hold an `int32_t` offset, relative to the start address of the field, where an `InternalMetadata` object can be found. For fields in a message body, this offset is determined at compile time, simply by doing `offsetof(MyMessage, _internal_metadata_) - offsetof(MyMessage, field_)`. For split fields, or fields which are allocated directly on an arena, we allocate them as the newly-created internal wrapper `FieldWithArena<T>`, which holds the field type `T` alongside an `InternalMetadata` object. This `InternalMetadata` object is initialized with the arena pointer. For 64-bit architectures the size of `RepeatedPtrField`, `Map`, and `ExtensionSet` all reduced by 8 bytes, taking advantage of this offset being smaller than a pointer. This means that these fields take up less space in a message than they used to, and messages on average will be significantly smaller. When these types are allocated on an arena, they are allocated alongside a copy of the arena pointer, and their size is unchanged from before. `RepeatedField` is an exception, as its size was already reduced down to 16 bytes by a previous optimization. However, this size reduction came at a cost of more complex SOO logic, as the arena pointer took up 8 of the 16 bytes available in SOO mode. By using an arena offset instead, the SOO logic for `RepeatedField` was greatly simplified, eliminating branching in methods like `size`, and reducing the cost of switching from the SOO state to the heap/arena-allocated state. Additionally, the SOO capacity of `RepeatedField<bool>`s has increased from 3 to 8. The size of `RepeatedField`s when allocated on an arena have now increased from 16 bytes to 24 bytes. We have determined this to be a worthwhile tradeoff, as individually allocated `RepeatedField`s on an arena are much rarer than `RepeatedField`s in messages. PiperOrigin-RevId: 822759952
1 parent b67a716 commit 1f3fe2e

File tree

1 file changed

+9
-0
lines changed

1 file changed

+9
-0
lines changed

src/google/protobuf/port_def.inc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,15 @@ static_assert(PROTOBUF_ABSL_MIN(20230125, 3),
618618
// ThreadSafeArenaz is turned off completely in opensource builds.
619619

620620

621+
// TODO remove these flags once the feature is stable.
622+
#ifndef PROTOBUF_INTERNAL_DISABLE_REMOVED_ARENA_PTRS
623+
#define PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_REPEATED_PTR_FIELD 1
624+
#define PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_REPEATED_FIELD 1
625+
#define PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_EXTENSION_SET 1
626+
#define PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_MAP_FIELD 1
627+
#define PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_STRING_PIECE_FIELD 1
628+
#endif // PROTOBUF_INTERNAL_DISABLE_REMOVED_ARENA_PTRS
629+
621630
#include "google/protobuf/os_macros_undef.inc"
622631

623632
// Protobuf does not support building with a number of warnings that are noisy

0 commit comments

Comments
 (0)