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