• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "proto_bloat.h"
16 
17 #include <array>
18 #include <cstdint>
19 #include <string_view>
20 
21 #include "pw_containers/vector.h"
22 #include "pw_preprocessor/concat.h"
23 #include "pw_protobuf/decoder.h"
24 #include "pw_protobuf/encoder.h"
25 #include "pw_protobuf/internal/codegen.h"
26 #include "pw_protobuf/stream_decoder.h"
27 #include "pw_status/status.h"
28 #include "pw_stream/null_stream.h"
29 #include "pw_stream/stream.h"
30 
31 namespace pw::protobuf_size_report {
32 namespace {
33 
34 template <typename T>
GetIntegerArray()35 constexpr std::array<T, 4> GetIntegerArray() {
36   return std::array<T, 4>{958736, 2085792374, 0, 42};
37 }
38 
39 template <typename T>
GetIntegerVector()40 constexpr Vector<T, 4> GetIntegerVector() {
41   return Vector<T, 4>{958736, 2085792374, 0, 42};
42 }
43 
GetBoolArray()44 constexpr std::array<bool, 5> GetBoolArray() {
45   return std::array<bool, 5>{true, false, false, true, true};
46 }
47 
GetBoolVector()48 Vector<bool, 5> GetBoolVector() {
49   return Vector<bool, 5>{true, false, false, true, true};
50 }
51 
GetFloatArray()52 constexpr std::array<float, 5> GetFloatArray() {
53   return std::array<float, 5>{1.2f, 3.4f, 5.6e20f, 0.0789f, 0.0f};
54 }
55 
GetFloatVector()56 Vector<float, 5> GetFloatVector() {
57   return Vector<float, 5>{1.2f, 3.4f, 5.6e20f, 0.0789f, 0.0f};
58 }
59 
GetDoubleArray()60 constexpr std::array<double, 5> GetDoubleArray() {
61   return std::array<double, 5>{1.2, 3.4, 5.6e20, 0.0789, 0.0};
62 }
63 
GetDoubleVector()64 Vector<double, 5> GetDoubleVector() {
65   return Vector<double, 5>{1.2, 3.4, 5.6e20, 0.0789, 0.0};
66 }
67 
68 constexpr std::string_view kTestString("I eat chips too often");
69 
70 constexpr protobuf::internal::MessageField kFakeTable[] = {
71     {4567,
72      protobuf::WireType::kDelimited,
73      234567,
74      protobuf::internal::VarintType::kNormal,
75      false,
76      true,
77      true,
78      true,
79      protobuf::internal::CallbackType::kSingleField,
80      260,
81      840245,
82      nullptr},
83     {4567,
84      protobuf::WireType::kDelimited,
85      234567,
86      protobuf::internal::VarintType::kNormal,
87      false,
88      true,
89      true,
90      true,
91      protobuf::internal::CallbackType::kSingleField,
92      260,
93      840245,
94      nullptr}};
95 
96 class FakeMessageEncoder : public protobuf::StreamEncoder {
97  public:
FakeMessageEncoder(stream::Writer & writer)98   FakeMessageEncoder(stream::Writer& writer)
99       : protobuf::StreamEncoder(writer, ByteSpan()) {}
DoBloat()100   void DoBloat() { Write(ByteSpan(), kFakeTable).IgnoreError(); }
101 };
102 
103 class FakeMessageDecoder : public protobuf::StreamDecoder {
104  public:
FakeMessageDecoder(stream::Reader & reader)105   FakeMessageDecoder(stream::Reader& reader)
106       : protobuf::StreamDecoder(reader) {}
DoBloat()107   void DoBloat() { Read(ByteSpan(), kFakeTable).IgnoreError(); }
108 };
109 
CodeToSetUpSizeReportEnvironment()110 void CodeToSetUpSizeReportEnvironment() {
111   [[maybe_unused]] volatile auto arr1 = GetIntegerArray<uint32_t>();
112   [[maybe_unused]] volatile auto arr2 = GetIntegerArray<int32_t>();
113   [[maybe_unused]] volatile auto arr3 = GetIntegerArray<uint64_t>();
114   [[maybe_unused]] volatile auto arr4 = GetIntegerArray<int64_t>();
115 
116   [[maybe_unused]] volatile auto vec1 = GetIntegerVector<uint32_t>();
117   [[maybe_unused]] volatile auto vec2 = GetIntegerVector<int32_t>();
118   [[maybe_unused]] volatile auto vec3 = GetIntegerVector<uint64_t>();
119   [[maybe_unused]] volatile auto vec4 = GetIntegerVector<int64_t>();
120 
121   [[maybe_unused]] volatile auto bool1 = GetBoolArray();
122   [[maybe_unused]] volatile auto bool2 = GetBoolVector();
123 
124   [[maybe_unused]] volatile auto float1 = GetFloatArray();
125   [[maybe_unused]] volatile auto float2 = GetFloatVector();
126 
127   [[maybe_unused]] volatile auto double1 = GetDoubleArray();
128   [[maybe_unused]] volatile auto double2 = GetDoubleVector();
129 
130   [[maybe_unused]] volatile std::string_view test_string = kTestString;
131 
132   [[maybe_unused]] volatile stream::NullStream null_stream;
133 }
134 
Dependencies()135 void Dependencies() {
136   std::array<std::byte, 2> buffer;
137   stream::NullStream null_stream;
138   stream::MemoryWriter memory_writer(buffer);
139   memory_writer.Write(buffer).IgnoreError();
140   null_stream.Write(buffer).IgnoreError();
141   stream::MemoryReader memory_reader(buffer);
142   memory_reader.Read(buffer).IgnoreError();
143 }
144 
CodeToPullInProtoEncoder()145 void CodeToPullInProtoEncoder() {
146   std::array<std::byte, 1024> buffer;
147   protobuf::MemoryEncoder encoder(buffer);
148 
149   encoder.WriteUint32(1, 1).IgnoreError();
150   encoder.WritePackedUint32(1, GetIntegerArray<uint32_t>()).IgnoreError();
151   encoder.WriteRepeatedUint32(1, GetIntegerVector<uint32_t>()).IgnoreError();
152 
153   encoder.WriteInt32(1, 1).IgnoreError();
154   encoder.WritePackedInt32(1, GetIntegerArray<int32_t>()).IgnoreError();
155   encoder.WriteRepeatedInt32(1, GetIntegerVector<int32_t>()).IgnoreError();
156 
157   encoder.WriteUint64(1, 1).IgnoreError();
158   encoder.WritePackedUint64(1, GetIntegerArray<uint64_t>()).IgnoreError();
159   encoder.WriteRepeatedUint64(1, GetIntegerVector<uint64_t>()).IgnoreError();
160 
161   encoder.WriteInt64(1, 1).IgnoreError();
162   encoder.WritePackedInt64(1, GetIntegerArray<int64_t>()).IgnoreError();
163   encoder.WriteRepeatedInt64(1, GetIntegerVector<int64_t>()).IgnoreError();
164 
165   encoder.WriteSint32(1, 1).IgnoreError();
166   encoder.WritePackedSint32(1, GetIntegerArray<int32_t>()).IgnoreError();
167   encoder.WriteRepeatedSint32(1, GetIntegerVector<int32_t>()).IgnoreError();
168 
169   encoder.WriteSint64(1, 1).IgnoreError();
170   encoder.WritePackedSint64(1, GetIntegerArray<int64_t>()).IgnoreError();
171   encoder.WriteRepeatedSint64(1, GetIntegerVector<int64_t>()).IgnoreError();
172 
173   encoder.WriteFixed32(1, 1).IgnoreError();
174   encoder.WritePackedFixed32(1, GetIntegerArray<uint32_t>()).IgnoreError();
175   encoder.WriteRepeatedFixed32(1, GetIntegerVector<uint32_t>()).IgnoreError();
176 
177   encoder.WriteFixed64(1, 1).IgnoreError();
178   encoder.WritePackedFixed64(1, GetIntegerArray<uint64_t>()).IgnoreError();
179   encoder.WriteRepeatedFixed64(1, GetIntegerVector<uint64_t>()).IgnoreError();
180 
181   encoder.WriteSfixed32(1, 1).IgnoreError();
182   encoder.WritePackedSfixed32(1, GetIntegerArray<int32_t>()).IgnoreError();
183   encoder.WriteRepeatedSfixed32(1, GetIntegerVector<int32_t>()).IgnoreError();
184 
185   encoder.WriteSfixed64(1, 1).IgnoreError();
186   encoder.WritePackedSfixed64(1, GetIntegerArray<int64_t>()).IgnoreError();
187   encoder.WriteRepeatedSfixed64(1, GetIntegerVector<int64_t>()).IgnoreError();
188 
189   {
190     protobuf::StreamEncoder child = encoder.GetNestedEncoder(0xc01dfee7);
191 
192     child.WriteFloat(234, 3.14f).IgnoreError();
193     child.WritePackedFloat(234, GetFloatArray()).IgnoreError();
194     child.WriteRepeatedFloat(234, GetFloatVector()).IgnoreError();
195 
196     child.WriteFloat(234, 3.14).IgnoreError();
197     child.WritePackedDouble(234, GetDoubleArray()).IgnoreError();
198     child.WriteRepeatedDouble(234, GetDoubleVector()).IgnoreError();
199 
200     child.WriteBool(7, true).IgnoreError();
201     child.WritePackedBool(8, GetBoolArray()).IgnoreError();
202     child.WriteRepeatedBool(8, GetBoolVector()).IgnoreError();
203 
204     encoder.WriteBytes(93, as_bytes(span<const double>(GetDoubleArray())))
205         .IgnoreError();
206     encoder.WriteString(21343, kTestString).IgnoreError();
207   }
208 
209   stream::NullStream null_stream;
210   protobuf::StreamEncoder stream_encoder(null_stream, buffer);
211   stream_encoder.WriteBytesFromStream(3636, null_stream, 10824, buffer)
212       .IgnoreError();
213 }
214 
CodeToPullInTableEncoder()215 void CodeToPullInTableEncoder() {
216   stream::NullStream stream;
217   FakeMessageEncoder fake_encoder(stream);
218   fake_encoder.DoBloat();
219 }
220 
CodeToPullInTableDecoder()221 void CodeToPullInTableDecoder() {
222   stream::NullStream stream;
223   FakeMessageDecoder fake_decoder(stream);
224   fake_decoder.DoBloat();
225 }
226 
227 #define _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(type_camel_case, underlying_type) \
228   do {                                                                         \
229     Status status;                                                             \
230     Vector<underlying_type, 3> vec;                                            \
231     span<underlying_type> packed_span;                                         \
232     status.Update(decoder.PW_CONCAT(Read, type_camel_case)().status());        \
233     status.Update(                                                             \
234         decoder.PW_CONCAT(ReadPacked, type_camel_case)(packed_span).status()); \
235     status.Update(decoder.PW_CONCAT(ReadRepeated, type_camel_case)(vec));      \
236     [[maybe_unused]] volatile bool ok = status.ok();                           \
237   } while (0)
238 
CodeToPullInProtoStreamDecoder()239 void CodeToPullInProtoStreamDecoder() {
240   stream::NullStream null_stream;
241   protobuf::StreamDecoder decoder(null_stream);
242   decoder.Next().IgnoreError();
243 
244   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Int32, int32_t);
245   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Uint32, uint32_t);
246   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Int64, int64_t);
247   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Uint64, uint64_t);
248 
249   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sint32, int32_t);
250   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sint64, int64_t);
251 
252   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Bool, bool);
253 
254   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Fixed32, uint32_t);
255   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Fixed64, uint64_t);
256   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sfixed32, int32_t);
257   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sfixed64, int64_t);
258 
259   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Float, float);
260   _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Double, double);
261 
262   {
263     Status status;
264     span<char> str_out;
265     span<std::byte> bytes_out;
266     status.Update(decoder.ReadString(str_out).status());
267     status.Update(decoder.ReadBytes(bytes_out).status());
268     status.Update(decoder.GetLengthDelimitedPayloadBounds().status());
269     [[maybe_unused]] volatile Result<uint32_t> field_number =
270         decoder.FieldNumber();
271     [[maybe_unused]] volatile protobuf::StreamDecoder::BytesReader
272         bytes_reader = decoder.GetBytesReader();
273     [[maybe_unused]] volatile bool ok = status.ok();
274   }
275 }
276 
277 #define _PW_USE_FUNCTIONS_FOR_DECODER(type_camel_case, underlying_type) \
278   do {                                                                  \
279     Status status;                                                      \
280     underlying_type val;                                                \
281     status.Update(decoder.PW_CONCAT(Read, type_camel_case)(&val));      \
282     [[maybe_unused]] volatile bool ok = status.ok();                    \
283   } while (0)
284 
CodeToPullInProtoDecoder()285 void CodeToPullInProtoDecoder() {
286   std::array<std::byte, 3> buffer = {
287       std::byte(0x01), std::byte(0xff), std::byte(0x08)};
288   protobuf::Decoder decoder(buffer);
289   decoder.Next().IgnoreError();
290 
291   _PW_USE_FUNCTIONS_FOR_DECODER(Int32, int32_t);
292   _PW_USE_FUNCTIONS_FOR_DECODER(Uint32, uint32_t);
293   _PW_USE_FUNCTIONS_FOR_DECODER(Int64, int64_t);
294   _PW_USE_FUNCTIONS_FOR_DECODER(Uint64, uint64_t);
295 
296   _PW_USE_FUNCTIONS_FOR_DECODER(Sint32, int32_t);
297   _PW_USE_FUNCTIONS_FOR_DECODER(Sint64, int64_t);
298 
299   _PW_USE_FUNCTIONS_FOR_DECODER(Bool, bool);
300 
301   _PW_USE_FUNCTIONS_FOR_DECODER(Fixed32, uint32_t);
302   _PW_USE_FUNCTIONS_FOR_DECODER(Fixed64, uint64_t);
303   _PW_USE_FUNCTIONS_FOR_DECODER(Sfixed32, int32_t);
304   _PW_USE_FUNCTIONS_FOR_DECODER(Sfixed64, int64_t);
305 
306   _PW_USE_FUNCTIONS_FOR_DECODER(Float, float);
307   _PW_USE_FUNCTIONS_FOR_DECODER(Double, double);
308 
309   {
310     Status status;
311     std::string_view str_out;
312     span<const std::byte> bytes_out;
313     status.Update(decoder.ReadString(&str_out));
314     status.Update(decoder.ReadBytes(&bytes_out));
315     decoder.Reset(buffer);
316     [[maybe_unused]] volatile uint32_t field_number = decoder.FieldNumber();
317     [[maybe_unused]] volatile bool ok = status.ok();
318   }
319 }
320 
321 }  // namespace
322 
BloatWithBase()323 void BloatWithBase() {
324   CodeToSetUpSizeReportEnvironment();
325   Dependencies();
326 }
327 
BloatWithEncoder()328 void BloatWithEncoder() {
329   BloatWithBase();
330   CodeToPullInProtoEncoder();
331 }
332 
BloatWithTableEncoder()333 void BloatWithTableEncoder() {
334   BloatWithBase();
335   CodeToPullInTableEncoder();
336 }
337 
BloatWithTableDecoder()338 void BloatWithTableDecoder() {
339   BloatWithBase();
340   CodeToPullInTableDecoder();
341 }
342 
BloatWithStreamDecoder()343 void BloatWithStreamDecoder() {
344   BloatWithBase();
345   CodeToPullInProtoStreamDecoder();
346 }
347 
BloatWithDecoder()348 void BloatWithDecoder() {
349   BloatWithBase();
350   CodeToPullInProtoDecoder();
351 }
352 
353 }  // namespace pw::protobuf_size_report
354