// Copyright 2022 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "proto_bloat.h" #include #include #include #include "pw_containers/vector.h" #include "pw_preprocessor/concat.h" #include "pw_protobuf/decoder.h" #include "pw_protobuf/encoder.h" #include "pw_protobuf/internal/codegen.h" #include "pw_protobuf/stream_decoder.h" #include "pw_status/status.h" #include "pw_stream/null_stream.h" #include "pw_stream/stream.h" namespace pw::protobuf_size_report { namespace { template constexpr std::array GetIntegerArray() { return std::array{958736, 2085792374, 0, 42}; } template constexpr Vector GetIntegerVector() { return Vector{958736, 2085792374, 0, 42}; } constexpr std::array GetBoolArray() { return std::array{true, false, false, true, true}; } Vector GetBoolVector() { return Vector{true, false, false, true, true}; } constexpr std::array GetFloatArray() { return std::array{1.2f, 3.4f, 5.6e20f, 0.0789f, 0.0f}; } Vector GetFloatVector() { return Vector{1.2f, 3.4f, 5.6e20f, 0.0789f, 0.0f}; } constexpr std::array GetDoubleArray() { return std::array{1.2, 3.4, 5.6e20, 0.0789, 0.0}; } Vector GetDoubleVector() { return Vector{1.2, 3.4, 5.6e20, 0.0789, 0.0}; } constexpr std::string_view kTestString("I eat chips too often"); constexpr protobuf::internal::MessageField kFakeTable[] = { {4567, protobuf::WireType::kDelimited, 234567, protobuf::internal::VarintType::kNormal, false, true, true, true, protobuf::internal::CallbackType::kSingleField, 260, 840245, nullptr}, {4567, protobuf::WireType::kDelimited, 234567, protobuf::internal::VarintType::kNormal, false, true, true, true, protobuf::internal::CallbackType::kSingleField, 260, 840245, nullptr}}; class FakeMessageEncoder : public protobuf::StreamEncoder { public: FakeMessageEncoder(stream::Writer& writer) : protobuf::StreamEncoder(writer, ByteSpan()) {} void DoBloat() { Write(ByteSpan(), kFakeTable).IgnoreError(); } }; class FakeMessageDecoder : public protobuf::StreamDecoder { public: FakeMessageDecoder(stream::Reader& reader) : protobuf::StreamDecoder(reader) {} void DoBloat() { Read(ByteSpan(), kFakeTable).IgnoreError(); } }; void CodeToSetUpSizeReportEnvironment() { [[maybe_unused]] volatile auto arr1 = GetIntegerArray(); [[maybe_unused]] volatile auto arr2 = GetIntegerArray(); [[maybe_unused]] volatile auto arr3 = GetIntegerArray(); [[maybe_unused]] volatile auto arr4 = GetIntegerArray(); [[maybe_unused]] volatile auto vec1 = GetIntegerVector(); [[maybe_unused]] volatile auto vec2 = GetIntegerVector(); [[maybe_unused]] volatile auto vec3 = GetIntegerVector(); [[maybe_unused]] volatile auto vec4 = GetIntegerVector(); [[maybe_unused]] volatile auto bool1 = GetBoolArray(); [[maybe_unused]] volatile auto bool2 = GetBoolVector(); [[maybe_unused]] volatile auto float1 = GetFloatArray(); [[maybe_unused]] volatile auto float2 = GetFloatVector(); [[maybe_unused]] volatile auto double1 = GetDoubleArray(); [[maybe_unused]] volatile auto double2 = GetDoubleVector(); [[maybe_unused]] volatile std::string_view test_string = kTestString; [[maybe_unused]] volatile stream::NullStream null_stream; } void Dependencies() { std::array buffer; stream::NullStream null_stream; stream::MemoryWriter memory_writer(buffer); memory_writer.Write(buffer).IgnoreError(); null_stream.Write(buffer).IgnoreError(); stream::MemoryReader memory_reader(buffer); memory_reader.Read(buffer).IgnoreError(); } void CodeToPullInProtoEncoder() { std::array buffer; protobuf::MemoryEncoder encoder(buffer); encoder.WriteUint32(1, 1).IgnoreError(); encoder.WritePackedUint32(1, GetIntegerArray()).IgnoreError(); encoder.WriteRepeatedUint32(1, GetIntegerVector()).IgnoreError(); encoder.WriteInt32(1, 1).IgnoreError(); encoder.WritePackedInt32(1, GetIntegerArray()).IgnoreError(); encoder.WriteRepeatedInt32(1, GetIntegerVector()).IgnoreError(); encoder.WriteUint64(1, 1).IgnoreError(); encoder.WritePackedUint64(1, GetIntegerArray()).IgnoreError(); encoder.WriteRepeatedUint64(1, GetIntegerVector()).IgnoreError(); encoder.WriteInt64(1, 1).IgnoreError(); encoder.WritePackedInt64(1, GetIntegerArray()).IgnoreError(); encoder.WriteRepeatedInt64(1, GetIntegerVector()).IgnoreError(); encoder.WriteSint32(1, 1).IgnoreError(); encoder.WritePackedSint32(1, GetIntegerArray()).IgnoreError(); encoder.WriteRepeatedSint32(1, GetIntegerVector()).IgnoreError(); encoder.WriteSint64(1, 1).IgnoreError(); encoder.WritePackedSint64(1, GetIntegerArray()).IgnoreError(); encoder.WriteRepeatedSint64(1, GetIntegerVector()).IgnoreError(); encoder.WriteFixed32(1, 1).IgnoreError(); encoder.WritePackedFixed32(1, GetIntegerArray()).IgnoreError(); encoder.WriteRepeatedFixed32(1, GetIntegerVector()).IgnoreError(); encoder.WriteFixed64(1, 1).IgnoreError(); encoder.WritePackedFixed64(1, GetIntegerArray()).IgnoreError(); encoder.WriteRepeatedFixed64(1, GetIntegerVector()).IgnoreError(); encoder.WriteSfixed32(1, 1).IgnoreError(); encoder.WritePackedSfixed32(1, GetIntegerArray()).IgnoreError(); encoder.WriteRepeatedSfixed32(1, GetIntegerVector()).IgnoreError(); encoder.WriteSfixed64(1, 1).IgnoreError(); encoder.WritePackedSfixed64(1, GetIntegerArray()).IgnoreError(); encoder.WriteRepeatedSfixed64(1, GetIntegerVector()).IgnoreError(); { protobuf::StreamEncoder child = encoder.GetNestedEncoder(0xc01dfee7); child.WriteFloat(234, 3.14f).IgnoreError(); child.WritePackedFloat(234, GetFloatArray()).IgnoreError(); child.WriteRepeatedFloat(234, GetFloatVector()).IgnoreError(); child.WriteFloat(234, 3.14).IgnoreError(); child.WritePackedDouble(234, GetDoubleArray()).IgnoreError(); child.WriteRepeatedDouble(234, GetDoubleVector()).IgnoreError(); child.WriteBool(7, true).IgnoreError(); child.WritePackedBool(8, GetBoolArray()).IgnoreError(); child.WriteRepeatedBool(8, GetBoolVector()).IgnoreError(); encoder.WriteBytes(93, as_bytes(span(GetDoubleArray()))) .IgnoreError(); encoder.WriteString(21343, kTestString).IgnoreError(); } stream::NullStream null_stream; protobuf::StreamEncoder stream_encoder(null_stream, buffer); stream_encoder.WriteBytesFromStream(3636, null_stream, 10824, buffer) .IgnoreError(); } void CodeToPullInTableEncoder() { stream::NullStream stream; FakeMessageEncoder fake_encoder(stream); fake_encoder.DoBloat(); } void CodeToPullInTableDecoder() { stream::NullStream stream; FakeMessageDecoder fake_decoder(stream); fake_decoder.DoBloat(); } #define _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(type_camel_case, underlying_type) \ do { \ Status status; \ Vector vec; \ span packed_span; \ status.Update(decoder.PW_CONCAT(Read, type_camel_case)().status()); \ status.Update( \ decoder.PW_CONCAT(ReadPacked, type_camel_case)(packed_span).status()); \ status.Update(decoder.PW_CONCAT(ReadRepeated, type_camel_case)(vec)); \ [[maybe_unused]] volatile bool ok = status.ok(); \ } while (0) void CodeToPullInProtoStreamDecoder() { stream::NullStream null_stream; protobuf::StreamDecoder decoder(null_stream); decoder.Next().IgnoreError(); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Int32, int32_t); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Uint32, uint32_t); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Int64, int64_t); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Uint64, uint64_t); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sint32, int32_t); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sint64, int64_t); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Bool, bool); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Fixed32, uint32_t); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Fixed64, uint64_t); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sfixed32, int32_t); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sfixed64, int64_t); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Float, float); _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Double, double); { Status status; span str_out; span bytes_out; status.Update(decoder.ReadString(str_out).status()); status.Update(decoder.ReadBytes(bytes_out).status()); status.Update(decoder.GetLengthDelimitedPayloadBounds().status()); [[maybe_unused]] volatile Result field_number = decoder.FieldNumber(); [[maybe_unused]] volatile protobuf::StreamDecoder::BytesReader bytes_reader = decoder.GetBytesReader(); [[maybe_unused]] volatile bool ok = status.ok(); } } #define _PW_USE_FUNCTIONS_FOR_DECODER(type_camel_case, underlying_type) \ do { \ Status status; \ underlying_type val; \ status.Update(decoder.PW_CONCAT(Read, type_camel_case)(&val)); \ [[maybe_unused]] volatile bool ok = status.ok(); \ } while (0) void CodeToPullInProtoDecoder() { std::array buffer = { std::byte(0x01), std::byte(0xff), std::byte(0x08)}; protobuf::Decoder decoder(buffer); decoder.Next().IgnoreError(); _PW_USE_FUNCTIONS_FOR_DECODER(Int32, int32_t); _PW_USE_FUNCTIONS_FOR_DECODER(Uint32, uint32_t); _PW_USE_FUNCTIONS_FOR_DECODER(Int64, int64_t); _PW_USE_FUNCTIONS_FOR_DECODER(Uint64, uint64_t); _PW_USE_FUNCTIONS_FOR_DECODER(Sint32, int32_t); _PW_USE_FUNCTIONS_FOR_DECODER(Sint64, int64_t); _PW_USE_FUNCTIONS_FOR_DECODER(Bool, bool); _PW_USE_FUNCTIONS_FOR_DECODER(Fixed32, uint32_t); _PW_USE_FUNCTIONS_FOR_DECODER(Fixed64, uint64_t); _PW_USE_FUNCTIONS_FOR_DECODER(Sfixed32, int32_t); _PW_USE_FUNCTIONS_FOR_DECODER(Sfixed64, int64_t); _PW_USE_FUNCTIONS_FOR_DECODER(Float, float); _PW_USE_FUNCTIONS_FOR_DECODER(Double, double); { Status status; std::string_view str_out; span bytes_out; status.Update(decoder.ReadString(&str_out)); status.Update(decoder.ReadBytes(&bytes_out)); decoder.Reset(buffer); [[maybe_unused]] volatile uint32_t field_number = decoder.FieldNumber(); [[maybe_unused]] volatile bool ok = status.ok(); } } } // namespace void BloatWithBase() { CodeToSetUpSizeReportEnvironment(); Dependencies(); } void BloatWithEncoder() { BloatWithBase(); CodeToPullInProtoEncoder(); } void BloatWithTableEncoder() { BloatWithBase(); CodeToPullInTableEncoder(); } void BloatWithTableDecoder() { BloatWithBase(); CodeToPullInTableDecoder(); } void BloatWithStreamDecoder() { BloatWithBase(); CodeToPullInProtoStreamDecoder(); } void BloatWithDecoder() { BloatWithBase(); CodeToPullInProtoDecoder(); } } // namespace pw::protobuf_size_report