Skip to content

Commit 3a3b7e4

Browse files
Abseil Teamcopybara-github
authored andcommitted
Reduce memory consumption of structured logging proto encoding by passing tag value
The proto encoding for structured logging currently pessimistically assumes each numeric tag value for encoded fields could be up to `UINT64_MAX`. In practice, the tag values we care about are all < 16, which only requires 1 byte of buffer space. This CL improves the memory consumption by specifying the tag value when calculating the buffer size needed for the structured logging proto. PiperOrigin-RevId: 696118135 Change-Id: Iee67deef568cb4df7646d3ddd40c14b490ca0e45
1 parent 27a0c73 commit 3a3b7e4

File tree

3 files changed

+37
-28
lines changed

3 files changed

+37
-28
lines changed

absl/log/internal/log_message.cc

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -578,16 +578,17 @@ void LogMessage::LogBacktraceIfNeeded() {
578578
template <LogMessage::StringType str_type>
579579
void LogMessage::CopyToEncodedBuffer(absl::string_view str) {
580580
auto encoded_remaining_copy = data_->encoded_remaining();
581+
constexpr uint8_t tag_value = str_type == StringType::kLiteral
582+
? ValueTag::kStringLiteral
583+
: ValueTag::kString;
581584
auto start = EncodeMessageStart(
582-
EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + str.size(),
585+
EventTag::kValue,
586+
BufferSizeFor(tag_value, WireType::kLengthDelimited) + str.size(),
583587
&encoded_remaining_copy);
584588
// If the `logging.proto.Event.value` field header did not fit,
585589
// `EncodeMessageStart` will have zeroed `encoded_remaining_copy`'s size and
586590
// `EncodeStringTruncate` will fail too.
587-
if (EncodeStringTruncate(str_type == StringType::kLiteral
588-
? ValueTag::kStringLiteral
589-
: ValueTag::kString,
590-
str, &encoded_remaining_copy)) {
591+
if (EncodeStringTruncate(tag_value, str, &encoded_remaining_copy)) {
591592
// The string may have been truncated, but the field header fit.
592593
EncodeMessageLength(start, &encoded_remaining_copy);
593594
data_->encoded_remaining() = encoded_remaining_copy;
@@ -604,13 +605,14 @@ template void LogMessage::CopyToEncodedBuffer<
604605
template <LogMessage::StringType str_type>
605606
void LogMessage::CopyToEncodedBuffer(char ch, size_t num) {
606607
auto encoded_remaining_copy = data_->encoded_remaining();
608+
constexpr uint8_t tag_value = str_type == StringType::kLiteral
609+
? ValueTag::kStringLiteral
610+
: ValueTag::kString;
607611
auto value_start = EncodeMessageStart(
608-
EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + num,
612+
EventTag::kValue,
613+
BufferSizeFor(tag_value, WireType::kLengthDelimited) + num,
609614
&encoded_remaining_copy);
610-
auto str_start = EncodeMessageStart(str_type == StringType::kLiteral
611-
? ValueTag::kStringLiteral
612-
: ValueTag::kString,
613-
num, &encoded_remaining_copy);
615+
auto str_start = EncodeMessageStart(tag_value, num, &encoded_remaining_copy);
614616
if (str_start.data()) {
615617
// The field headers fit.
616618
log_internal::AppendTruncated(ch, num, encoded_remaining_copy);

absl/log/internal/proto.cc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ void EncodeRawVarint(uint64_t value, size_t size, absl::Span<char> *buf) {
3535
}
3636
buf->remove_prefix(size);
3737
}
38-
constexpr uint64_t MakeTagType(uint64_t tag, WireType type) {
39-
return tag << 3 | static_cast<uint64_t>(type);
40-
}
4138
} // namespace
4239

4340
bool EncodeVarint(uint64_t tag, uint64_t value, absl::Span<char> *buf) {

absl/log/internal/proto.h

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -199,23 +199,33 @@ constexpr uint64_t MaxVarintForSize(size_t size) {
199199
return size >= 10 ? (std::numeric_limits<uint64_t>::max)()
200200
: (static_cast<uint64_t>(1) << size * 7) - 1;
201201
}
202+
constexpr uint64_t MakeTagType(uint64_t tag, WireType type) {
203+
return tag << 3 | static_cast<uint64_t>(type);
204+
}
202205

203206
// `BufferSizeFor` returns a number of bytes guaranteed to be sufficient to
204-
// store encoded fields of the specified WireTypes regardless of tag numbers and
205-
// data values. This only makes sense for `WireType::kLengthDelimited` if you
206-
// add in the length of the contents yourself, e.g. for string and bytes fields
207-
// by adding the lengths of any encoded strings to the return value or for
208-
// submessage fields by enumerating the fields you may encode into their
209-
// contents.
210-
constexpr size_t BufferSizeFor() { return 0; }
211-
template <typename... T>
212-
constexpr size_t BufferSizeFor(WireType type, T... tail) {
213-
// tag_type + data + ...
214-
return MaxVarintSize() +
215-
(type == WireType::kVarint ? MaxVarintSize() : //
216-
type == WireType::k64Bit ? 8 : //
217-
type == WireType::k32Bit ? 4 : MaxVarintSize()) + //
218-
BufferSizeFor(tail...);
207+
// store encoded fields as `(tag, WireType)`, regardless of data values. This
208+
// only makes sense for `WireType::kLengthDelimited` if you add in the length of
209+
// the contents yourself, e.g. for string and bytes fields by adding the lengths
210+
// of any encoded strings to the return value or for submessage fields by
211+
// enumerating the fields you may encode into their contents.
212+
constexpr size_t BufferSizeFor(uint64_t tag, WireType type) {
213+
size_t buffer_size = VarintSize(MakeTagType(tag, type));
214+
switch (type) {
215+
case WireType::kVarint:
216+
buffer_size += MaxVarintSize();
217+
break;
218+
case WireType::k64Bit:
219+
buffer_size += size_t{8};
220+
break;
221+
case WireType::kLengthDelimited:
222+
buffer_size += MaxVarintSize();
223+
break;
224+
case WireType::k32Bit:
225+
buffer_size += size_t{4};
226+
break;
227+
}
228+
return buffer_size;
219229
}
220230

221231
// absl::Span<const char> represents a view into the un-processed space in a

0 commit comments

Comments
 (0)