pw_protobuf extended size report#

pw_protobuf: Expressive interface for encoding and decoding protocol buffers

pw_protobuf can impact binary size very differently depending on how it’s used. A series of examples are provided below to illustrate how much certain use cases affect binary size.

Overview#

This module includes a proto encoder, two different proto decoders (one that operates on a pw::stream::StreamReader and another that operates on an in- memory buffer), codegen for direct wire-format encoders/decoders, and a table-based codegen system for constructing proto messages as in-memory structs.

Here’s a brief overview of the different encoder/decoder costs:

Label

Segment

Delta

Full wire-format proto encode/decode library

FLASH

+24

[section .code]

+2

pw::protobuf::StreamEncoder::Write()::_pw_tokenizer_string_entry_555_35

+6

pw::protobuf::StreamEncoder::Write()::_pw_tokenizer_string_entry_543_33

-146

pw::protobuf::StreamDecoder::ReadFieldKey()::_pw_tokenizer_string_entry_228_13

-26

pw::protobuf::StreamDecoder::SkipField()::_pw_tokenizer_string_entry_266_15

+28

pw::protobuf::StreamDecoder::~StreamDecoder()::_pw_tokenizer_string_entry_111_1

+74

pw::protobuf::StreamEncoder::Write()::_pw_tokenizer_string_entry_490_29

+98

pw::protobuf::StreamEncoder::Write()::_pw_tokenizer_string_entry_365_27

NEW

+184

pw::protobuf::StreamEncoder::GetNestedEncoder()

NEW

+180

pw::protobuf::StreamDecoder::ReadOneVarint()

NEW

+176

pw::protobuf::StreamDecoder::ReadFieldKey()

NEW

+168

pw::protobuf::StreamEncoder::WriteLengthDelimitedFieldFromStream()

NEW

+164

pw::protobuf::StreamDecoder::ReadPackedVarintField()

NEW

+156

pw::protobuf::Decoder::GetFieldSize()

NEW

+156

pw::protobuf::StreamEncoder::WritePackedFixed()

NEW

+148

pw::protobuf::StreamDecoder::SkipField()

NEW

+106

pw::protobuf::StreamDecoder::ReadPackedFixedField()

NEW

+104

pw::protobuf::StreamEncoder::UpdateStatusForWrite()

NEW

+100

pw::protobuf::Decoder::ReadDelimited()

NEW

+98

pw::protobuf::StreamDecoder::BytesReader::DoSeek()

NEW

+98

pw::protobuf::StreamDecoder::ReadDelimitedField()

NEW

+96

pw::protobuf::StreamEncoder::CloseNestedMessage()

NEW

+92

pw::protobuf::Decoder::ConsumeKey()

NEW

+92

pw::protobuf::StreamEncoder::WriteVarintField()

NEW

+88

pw::protobuf::StreamDecoder::GetBytesReader()

NEW

+88

pw::protobuf::StreamDecoder::ReadFixedField()

NEW

+84

pw::protobuf::StreamDecoder::BytesReader::DoRead()

NEW

+80

pw::protobuf::StreamDecoder::ReadVarintField()

NEW

+80

pw::protobuf::StreamEncoder::WriteFixed()

NEW

+76

pw::protobuf::StreamDecoder::Advance()

NEW

+72

pw::protobuf::FieldKey::IsValidKey()

NEW

+68

pw::protobuf::StreamDecoder::CheckOkToRead()

NEW

+68

pw::protobuf::StreamDecoder::CloseNestedDecoder()

NEW

+68

pw::protobuf::StreamDecoder::Next()

NEW

+68

pw::protobuf::StreamEncoder::WriteLengthDelimitedField()

NEW

+60

pw::protobuf::Decoder::ReadFixed()

NEW

+58

pw::protobuf::Decoder::SkipField()

NEW

+56

pw::protobuf::Decoder::FieldNumber()

NEW

+54

pw::protobuf::Decoder::ReadSint64()

NEW

+50

pw::protobuf::Decoder::Next()

NEW

+48

pw::protobuf::StreamDecoder::~StreamDecoder()

NEW

+46

pw::protobuf::Decoder::ReadSint32()

NEW

+46

pw::protobuf::Decoder::ReadVarint()

NEW

+44

pw::protobuf::FieldKey::FieldKey()

NEW

+44

pw::protobuf::WriteLengthDelimitedKeyAndLengthPrefix()

NEW

+40

pw::protobuf::StreamDecoder::GetLengthDelimitedPayloadBounds()

NEW

+40

pw::protobuf::StreamEncoder::CloseEncoder()

NEW

+38

pw::protobuf::TagSizeBytes<>()

NEW

+36

pw::protobuf::StreamDecoder::BytesReader

NEW

+36

pw::protobuf::StreamDecoder::CloseBytesReader()

NEW

+32

pw::protobuf::Decoder::ReadUint32()

NEW

+32

pw::protobuf::SizeOfDelimitedFieldWithoutValue<>()

NEW

+30

pw::protobuf::Decoder::ReadBool()

NEW

+26

pw::protobuf::Decoder::ReadString()

NEW

+26

pw::protobuf::SizeOfField<>()

NEW

+16

pw::protobuf::StreamDecoder::BytesReader::~BytesReader()

NEW

+12

pw::protobuf::SizeOfDelimitedField<>()

+3,888

Including table-based Message encoder and decoder

FLASH

+24

[section .code]

-98

pw::protobuf::StreamDecoder::ReadVarintField()::_pw_tokenizer_string_entry_318_17

+2

pw::protobuf::StreamEncoder::Write()::_pw_tokenizer_string_entry_555_35

+6

pw::protobuf::StreamEncoder::Write()::_pw_tokenizer_string_entry_543_33

-74

pw::protobuf::StreamDecoder::SkipField()::_pw_tokenizer_string_entry_266_15

+28

pw::protobuf::StreamDecoder::~StreamDecoder()::_pw_tokenizer_string_entry_111_1

+74

pw::protobuf::StreamEncoder::Write()::_pw_tokenizer_string_entry_490_29

+98

pw::protobuf::StreamEncoder::Write()::_pw_tokenizer_string_entry_365_27

NEW

+1,176

pw::protobuf::StreamEncoder::Write()

NEW

+800

pw::protobuf::StreamDecoder::Read()

NEW

+184

pw::protobuf::StreamEncoder::GetNestedEncoder()

NEW

+180

pw::protobuf::StreamDecoder::ReadOneVarint()

NEW

+176

pw::protobuf::StreamDecoder::ReadFieldKey()

NEW

+168

pw::protobuf::StreamEncoder::WriteLengthDelimitedFieldFromStream()

NEW

+164

pw::protobuf::StreamDecoder::ReadPackedVarintField()

NEW

+156

pw::protobuf::Decoder::GetFieldSize()

NEW

+156

pw::protobuf::StreamEncoder::WritePackedFixed()

NEW

+148

pw::protobuf::StreamDecoder::SkipField()

NEW

+120

pw::protobuf::StreamDecoder::ReadStringOrBytesField<>()

NEW

+106

pw::protobuf::StreamDecoder::ReadPackedFixedField()

NEW

+104

pw::protobuf::StreamEncoder::UpdateStatusForWrite()

NEW

+100

pw::protobuf::Decoder::ReadDelimited()

NEW

+98

pw::protobuf::StreamDecoder::BytesReader::DoSeek()

NEW

+98

pw::protobuf::StreamDecoder::ReadDelimitedField()

NEW

+96

pw::protobuf::StreamEncoder::CloseNestedMessage()

NEW

+96

pw::protobuf::StreamEncoder::ResetOneOfCallbacks()

NEW

+92

pw::protobuf::Decoder::ConsumeKey()

NEW

+92

pw::protobuf::StreamEncoder::WriteVarintField()

NEW

+88

pw::protobuf::StreamDecoder::GetBytesReader()

NEW

+88

pw::protobuf::StreamDecoder::ReadFixedField()

NEW

+84

pw::protobuf::StreamDecoder::BytesReader::DoRead()

NEW

+80

pw::protobuf::StreamDecoder::GetNestedDecoder()

NEW

+80

pw::protobuf::StreamDecoder::ReadVarintField()

NEW

+80

pw::protobuf::StreamDecoder::StreamDecoder()

NEW

+80

pw::protobuf::StreamEncoder::WriteFixed()

NEW

+76

pw::protobuf::StreamDecoder::Advance()

NEW

+72

pw::protobuf::FieldKey::IsValidKey()

NEW

+68

pw::protobuf::StreamDecoder::CheckOkToRead()

NEW

+68

pw::protobuf::StreamDecoder::CloseNestedDecoder()

NEW

+68

pw::protobuf::StreamDecoder::Next()

NEW

+68

pw::protobuf::StreamEncoder::WriteLengthDelimitedField()

NEW

+60

pw::protobuf::Decoder::ReadFixed()

NEW

+58

pw::protobuf::Decoder::SkipField()

NEW

+56

pw::protobuf::Decoder::FieldNumber()

NEW

+54

pw::protobuf::Decoder::ReadSint64()

NEW

+54

pw::protobuf::OneOf<>::Decode()

NEW

+50

pw::protobuf::Decoder::Next()

NEW

+48

pw::protobuf::StreamDecoder::~StreamDecoder()

NEW

+46

pw::protobuf::Decoder::ReadSint32()

NEW

+46

pw::protobuf::Decoder::ReadVarint()

NEW

+44

pw::protobuf::FieldKey::FieldKey()

NEW

+44

pw::protobuf::OneOf<>::Encode()

NEW

+44

pw::protobuf::WriteLengthDelimitedKeyAndLengthPrefix()

NEW

+40

pw::protobuf::StreamDecoder::GetLengthDelimitedPayloadBounds()

NEW

+40

pw::protobuf::StreamEncoder::CloseEncoder()

NEW

+38

pw::protobuf::TagSizeBytes<>()

NEW

+36

pw::protobuf::StreamDecoder::BytesReader

NEW

+36

pw::protobuf::StreamDecoder::CloseBytesReader()

NEW

+34

pw::protobuf::Callback<>::Decode()

NEW

+34

pw::protobuf::Callback<>::Encode()

NEW

+32

pw::protobuf::Decoder::ReadUint32()

NEW

+32

pw::protobuf::SizeOfDelimitedFieldWithoutValue<>()

NEW

+30

pw::protobuf::Decoder::ReadBool()

NEW

+28

pw::protobuf::SizeOfField<>()

NEW

+26

pw::protobuf::Decoder::ReadString()

NEW

+18

pw::protobuf::StreamEncoder::WriteStringOrBytes<>()

NEW

+16

pw::protobuf::StreamDecoder::BytesReader::~BytesReader()

NEW

+12

pw::protobuf::SizeOfDelimitedField<>()

+6,426

Note

There’s some overhead involved in ensuring all of the encoder/decoder functionality is pulled in. Check the per-symbol breakdown for more details.

Encoder/decoder codegen overhead#

The different proto serialization/deserialization codegen methods have different overhead. Some have a higher up-front cost, but lower complexity (and therefore smaller compiler generated code) at the sites of usage. Others trade lower up-front code size cost for more complexity at the proto construction and read sites.

This example uses the following proto message to construct a variety of use cases to illustrate how code and memory requirements can change depending on the complexity of the proto message being encoded/decoded.

syntax = "proto3";

package pw.protobuf_size_report;

message ItemInfo {
  enum Access {
    NONE = 0;
    READ = 1;
    WRITE = 2;
    READ_AND_WRITE = 3;
  }
  uint64 offset = 1;
  uint32 size = 2;
  Access access_level = 3;
}

message ResponseInfo {
  oneof key {
    string key_string = 1;
    fixed32 key_token = 2;
  }

  optional int64 timestamp = 3;
  optional bool has_value = 4;
  ItemInfo item_info = 5;
}

message Response {
  repeated ResponseInfo responses = 1;
}

message LookupRequest {
  message AuthInfo {
    optional uint32 id = 1;
    optional uint32 token = 2;
  }
  oneof key {
    string key_string = 1;
    fixed32 key_token = 2;
  }
  optional uint32 items_per_response = 3;
  AuthInfo auth_info = 4;
  bool add_timestamp = 5;
}

This proto is configured with the following options file:


pw.protobuf_size_report.Reponse.responses max_count:4

Trivial proto#

This is a size report for encoding/decoding the pw.protobuf.test.ItemInfo message. This is a pretty trivial message with just a few integers.

Label

Segment

Delta

Direct wire-format proto encoder

FLASH

NEW

+80

pw::protobuf_size_report::(anonymous namespace)::BasicDecode()

NEW

+60

pw::protobuf_size_report::(anonymous namespace)::BasicEncode()

NEW

+20

pw::protobuf_size_report::(anonymous namespace)::ConsumeValue<>()

+160

RAM

NEW

+40

pw::protobuf_size_report::(anonymous namespace)::generic_encoder

NEW

+28

pw::protobuf_size_report::(anonymous namespace)::decode_buffer

NEW

+28

pw::protobuf_size_report::(anonymous namespace)::encode_buffer

NEW

+12

pw::protobuf_size_report::(anonymous namespace)::generic_decoder

+108

Generated wrapped wire-format encoder

FLASH

NEW

+92

pw::protobuf_size_report::(anonymous namespace)::BasicDecode()

NEW

+48

pw::protobuf_size_report::(anonymous namespace)::BasicEncode()

+140

RAM

NEW

+40

pw::protobuf_size_report::(anonymous namespace)::decoder

NEW

+40

pw::protobuf_size_report::(anonymous namespace)::encoder

NEW

+28

pw::protobuf_size_report::(anonymous namespace)::decode_buffer

NEW

+28

pw::protobuf_size_report::(anonymous namespace)::encode_buffer

NEW

+20

pw::protobuf_size_report::(anonymous namespace)::reader

+156

Generated message encoder

FLASH

NEW

+48

pw::protobuf_size_report::(anonymous namespace)::BasicEncode()

NEW

+48

pw::protobuf_size_report::pwpb::ItemInfo::_kMessageFields

NEW

+20

pw::protobuf_size_report::(anonymous namespace)::BasicDecode()

+116

RAM

NEW

+40

pw::protobuf_size_report::(anonymous namespace)::decoder

NEW

+40

pw::protobuf_size_report::(anonymous namespace)::encoder

NEW

+28

pw::protobuf_size_report::(anonymous namespace)::decode_buffer

NEW

+28

pw::protobuf_size_report::(anonymous namespace)::encode_buffer

NEW

+20

pw::protobuf_size_report::(anonymous namespace)::reader

NEW

+16

pw::protobuf_size_report::(anonymous namespace)::message

+172

Optional and oneof#

This is a size report for encoding/decoding the pw.protobuf.test.ResponseInfo message. This is slightly more complex message that has a few explicitly optional fields, a oneof, and a submessage.

Label

Segment

Delta

Direct wire-format proto encoder

FLASH

NEW

+208

pw::protobuf_size_report::(anonymous namespace)::BasicDecode()

NEW

+180

pw::protobuf_size_report::(anonymous namespace)::BasicEncode()

NEW

+90

pw::protobuf_size_report::(anonymous namespace)::DecodeItemInfo()

NEW

+30

pw::protobuf_size_report::(anonymous namespace)::ConsumeValue<>()

+508

RAM

NEW

+40

pw::protobuf_size_report::(anonymous namespace)::encoder

NEW

+28

pw::protobuf_size_report::(anonymous namespace)::decode_buffer

NEW

+28

pw::protobuf_size_report::(anonymous namespace)::encode_buffer

NEW

+12

pw::protobuf_size_report::(anonymous namespace)::decoder

+108

Generated wrapped wire-format encoder

FLASH

NEW

+204

pw::protobuf_size_report::(anonymous namespace)::BasicDecode()

NEW

+156

pw::protobuf_size_report::(anonymous namespace)::BasicEncode()

NEW

+84

pw::protobuf_size_report::(anonymous namespace)::DecodeItemInfo()

NEW

+18

pw::protobuf_size_report::(anonymous namespace)::ConsumeValue<>()

+462

RAM

NEW

+49

pw::protobuf_size_report::(anonymous namespace)::decode_buffer

NEW

+47

pw::protobuf_size_report::(anonymous namespace)::encode_buffer

NEW

+40

pw::protobuf_size_report::(anonymous namespace)::decoder

NEW

+40

pw::protobuf_size_report::(anonymous namespace)::encoder

NEW

+20

pw::protobuf_size_report::(anonymous namespace)::reader

+196

Generated message encoder

FLASH

NEW

+132

pw::protobuf_size_report::(anonymous namespace)::BasicEncode()

NEW

+100

pw::protobuf_size_report::(anonymous namespace)::BasicDecode()

NEW

+80

pw::protobuf_size_report::pwpb::ResponseInfo::_kMessageFields

NEW

+48

pw::protobuf_size_report::pwpb::ItemInfo::_kMessageFields

NEW

+18

pw::protobuf_size_report::(anonymous namespace)::ConsumeValue<>()

NEW

+8

pw::protobuf_size_report::pwpb::ItemInfo::kMessageFields

+386

RAM

NEW

+56

pw::protobuf_size_report::(anonymous namespace)::message

NEW

+49

pw::protobuf_size_report::(anonymous namespace)::decode_buffer

NEW

+47

pw::protobuf_size_report::(anonymous namespace)::encode_buffer

NEW

+40

pw::protobuf_size_report::(anonymous namespace)::decoder

NEW

+40

pw::protobuf_size_report::(anonymous namespace)::encoder

NEW

+20

pw::protobuf_size_report::(anonymous namespace)::reader

+252