• 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 #include "pw_bloat/bloat_this_binary.h"
17 #include "pw_protobuf/decoder.h"
18 #include "pw_protobuf/encoder.h"
19 #include "pw_protobuf/stream_decoder.h"
20 #include "pw_protobuf_test_protos/size_report.pwpb.h"
21 #include "pw_result/result.h"
22 #include "pw_status/status.h"
23 
24 #ifndef _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
25 #define _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN 0
26 #endif  // _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
27 
28 #ifndef _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
29 #define _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT 0
30 #endif  // _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
31 
32 #ifndef _PW_PROTOBUF_SIZE_REPORT_MESSAGE
33 #define _PW_PROTOBUF_SIZE_REPORT_MESSAGE 0
34 #endif  // _PW_PROTOBUF_SIZE_REPORT_MESSAGE
35 
36 namespace pw::protobuf_size_report {
37 namespace {
38 
39 namespace ItemInfo = pwpb::ItemInfo;
40 namespace ResponseInfo = pwpb::ResponseInfo;
41 
42 template <typename T>
ConsumeValue(T val)43 PW_NO_INLINE void ConsumeValue(T val) {
44   [[maybe_unused]] volatile T no_optimize = val;
45 }
46 
47 #if _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
48 
49 std::array<std::byte, ItemInfo::kMaxEncodedSizeBytes> encode_buffer;
50 pw::protobuf::MemoryEncoder encoder(encode_buffer);
51 
BasicEncode()52 PW_NO_INLINE void BasicEncode() {
53   pw::Status status;
54   volatile enum KeyType : uint32_t {
55     NONE = 0,
56     KEY_STRING = 1,
57     KEY_TOKEN = 2,
58   } which_key = KeyType::KEY_STRING;
59   volatile bool has_timestamp = true;
60   volatile bool has_has_value = false;
61   if (which_key == KeyType::KEY_STRING) {
62     encoder.WriteString(1, "test");
63   } else if (which_key == KeyType::KEY_TOKEN) {
64     encoder.WriteFixed32(2, 99999);
65   }
66 
67   if (has_timestamp) {
68     encoder.WriteInt64(3, 1663003467);
69   }
70 
71   if (has_has_value) {
72     encoder.WriteBool(4, true);
73   }
74 
75   {
76     pw::protobuf::StreamEncoder submessage_encoder =
77         encoder.GetNestedEncoder(5);
78     status.Update(submessage_encoder.WriteInt64(1, 0x5001DBADFEEDBEE5));
79     status.Update(submessage_encoder.WriteInt32(2, 128));
80     status.Update(submessage_encoder.WriteInt32(3, 2));
81   }
82   ConsumeValue(status);
83 }
84 
85 std::array<std::byte, ItemInfo::kMaxEncodedSizeBytes> decode_buffer;
86 pw::protobuf::Decoder decoder(decode_buffer);
87 
DecodeItemInfo(pw::ConstByteSpan data)88 PW_NO_INLINE void DecodeItemInfo(pw::ConstByteSpan data) {
89   pw::protobuf::Decoder submessage_decoder(data);
90   while (submessage_decoder.Next().ok()) {
91     switch (submessage_decoder.FieldNumber()) {
92       case static_cast<uint32_t>(ItemInfo::Fields::kOffset): {
93         uint64_t value;
94         if (submessage_decoder.ReadUint64(&value).ok()) {
95           ConsumeValue(value);
96         }
97         break;
98       }
99       case static_cast<uint32_t>(ItemInfo::Fields::kSize): {
100         uint32_t value;
101         if (submessage_decoder.ReadUint32(&value).ok()) {
102           ConsumeValue(value);
103         }
104         break;
105       }
106       case static_cast<uint32_t>(ItemInfo::Fields::kAccessLevel): {
107         uint32_t value;
108 
109         if (submessage_decoder.ReadUint32(&value).ok()) {
110           ConsumeValue(value);
111         }
112         break;
113       }
114     }
115   }
116 }
117 
BasicDecode()118 PW_NO_INLINE void BasicDecode() {
119   volatile enum KeyType : uint32_t {
120     NONE = 0,
121     KEY_STRING = 1,
122     KEY_TOKEN = 2,
123   } which_key = KeyType::NONE;
124   volatile bool has_timestamp = false;
125   volatile bool has_has_value = false;
126 
127   while (decoder.Next().ok()) {
128     switch (decoder.FieldNumber()) {
129       case static_cast<uint32_t>(ResponseInfo::Fields::kKeyString): {
130         which_key = KeyType::KEY_STRING;
131         std::string_view value;
132         if (decoder.ReadString(&value).ok()) {
133           ConsumeValue(value);
134         }
135         break;
136       }
137       case static_cast<uint32_t>(ResponseInfo::Fields::kKeyToken): {
138         which_key = KeyType::KEY_TOKEN;
139         uint32_t value;
140         if (decoder.ReadUint32(&value).ok()) {
141           ConsumeValue(value);
142         }
143         break;
144       }
145       case static_cast<uint32_t>(ResponseInfo::Fields::kTimestamp): {
146         uint64_t value;
147         has_timestamp = true;
148         if (decoder.ReadUint64(&value).ok()) {
149           ConsumeValue(value);
150         }
151         break;
152       }
153       case static_cast<uint32_t>(ResponseInfo::Fields::kHasValue): {
154         bool value;
155         has_has_value = true;
156         if (decoder.ReadBool(&value).ok()) {
157           ConsumeValue(value);
158         }
159         break;
160       }
161       case static_cast<uint32_t>(ResponseInfo::Fields::kItemInfo): {
162         pw::ConstByteSpan value;
163         if (decoder.ReadBytes(&value).ok()) {
164           DecodeItemInfo(value);
165         }
166         break;
167       }
168     }
169   }
170   ConsumeValue(which_key);
171   ConsumeValue(has_timestamp);
172   ConsumeValue(has_has_value);
173 }
174 
175 #endif  // _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
176 
177 #if _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
178 
179 std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> encode_buffer;
180 ResponseInfo::MemoryEncoder encoder(encode_buffer);
181 
BasicEncode()182 PW_NO_INLINE void BasicEncode() {
183   pw::Status status;
184   volatile enum KeyType : uint32_t {
185     NONE = 0,
186     KEY_STRING = 1,
187     KEY_TOKEN = 2,
188   } which_key = KeyType::KEY_STRING;
189   volatile bool has_timestamp = true;
190   volatile bool has_has_value = false;
191   if (which_key == KeyType::KEY_STRING) {
192     encoder.WriteKeyString("test");
193   } else if (which_key == KeyType::KEY_TOKEN) {
194     encoder.WriteKeyToken(99999);
195   }
196 
197   if (has_timestamp) {
198     encoder.WriteTimestamp(1663003467);
199   }
200 
201   if (has_has_value) {
202     encoder.WriteHasValue(true);
203   }
204 
205   {
206     ItemInfo::StreamEncoder submessage_encoder = encoder.GetItemInfoEncoder();
207     status.Update(submessage_encoder.WriteOffset(0x5001DBADFEEDBEE5));
208     status.Update(submessage_encoder.WriteSize(128));
209     status.Update(submessage_encoder.WriteAccessLevel(ItemInfo::Access::WRITE));
210   }
211   ConsumeValue(status);
212 }
213 
214 std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> decode_buffer;
215 pw::stream::MemoryReader reader(decode_buffer);
216 ResponseInfo::StreamDecoder decoder(reader);
217 
DecodeItemInfo(ItemInfo::StreamDecoder & submessage_decoder)218 PW_NO_INLINE void DecodeItemInfo(ItemInfo::StreamDecoder& submessage_decoder) {
219   while (submessage_decoder.Next().ok()) {
220     pw::Result<ItemInfo::Fields> field = submessage_decoder.Field();
221     if (!field.ok()) {
222       ConsumeValue(field.status());
223       return;
224     }
225 
226     switch (field.value()) {
227       case ItemInfo::Fields::kOffset: {
228         pw::Result<uint64_t> value = submessage_decoder.ReadOffset();
229         if (value.ok()) {
230           ConsumeValue(value);
231         }
232         break;
233       }
234       case ItemInfo::Fields::kSize: {
235         pw::Result<uint32_t> value = submessage_decoder.ReadSize();
236         if (value.ok()) {
237           ConsumeValue(value);
238         }
239         break;
240       }
241       case ItemInfo::Fields::kAccessLevel: {
242         pw::Result<ItemInfo::Access> value =
243             submessage_decoder.ReadAccessLevel();
244         if (value.ok()) {
245           ConsumeValue(value);
246         }
247         break;
248       }
249     }
250   }
251 }
252 
BasicDecode()253 PW_NO_INLINE void BasicDecode() {
254   volatile enum KeyType : uint32_t {
255     NONE = 0,
256     KEY_STRING = 1,
257     KEY_TOKEN = 2,
258   } which_key = KeyType::NONE;
259   volatile bool has_timestamp = false;
260   volatile bool has_has_value = false;
261 
262   while (decoder.Next().ok()) {
263     while (decoder.Next().ok()) {
264       pw::Result<ResponseInfo::Fields> field = decoder.Field();
265       if (!field.ok()) {
266         ConsumeValue(field.status());
267         return;
268       }
269 
270       switch (field.value()) {
271         case ResponseInfo::Fields::kKeyString: {
272           which_key = KeyType::KEY_STRING;
273           std::array<char, 8> value;
274           pw::StatusWithSize status = decoder.ReadKeyString(value);
275           if (status.ok()) {
276             ConsumeValue(pw::span(value));
277           }
278           break;
279         }
280         case ResponseInfo::Fields::kKeyToken: {
281           which_key = KeyType::KEY_TOKEN;
282           pw::Result<uint32_t> value = decoder.ReadKeyToken();
283           if (value.ok()) {
284             ConsumeValue(value);
285           }
286           break;
287         }
288         case ResponseInfo::Fields::kTimestamp: {
289           has_timestamp = true;
290           pw::Result<int64_t> value = decoder.ReadTimestamp();
291           if (value.ok()) {
292             ConsumeValue(value);
293           }
294           break;
295         }
296         case ResponseInfo::Fields::kHasValue: {
297           has_has_value = true;
298           pw::Result<bool> value = decoder.ReadHasValue();
299           if (value.ok()) {
300             ConsumeValue(value);
301           }
302           break;
303         }
304         case ResponseInfo::Fields::kItemInfo: {
305           ItemInfo::StreamDecoder submessage_decoder =
306               decoder.GetItemInfoDecoder();
307           DecodeItemInfo(submessage_decoder);
308           break;
309         }
310       }
311     }
312   }
313   ConsumeValue(which_key);
314   ConsumeValue(has_timestamp);
315   ConsumeValue(has_has_value);
316 }
317 #endif  // _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
318 
319 #if _PW_PROTOBUF_SIZE_REPORT_MESSAGE
320 
321 ResponseInfo::Message message;
322 
323 std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> encode_buffer;
324 ResponseInfo::MemoryEncoder encoder(encode_buffer);
325 
BasicEncode()326 PW_NO_INLINE void BasicEncode() {
327   volatile enum KeyType : uint32_t {
328     NONE = 0,
329     KEY_STRING = 1,
330     KEY_TOKEN = 2,
331   } which_key = KeyType::KEY_STRING;
332   volatile bool has_timestamp = true;
333   volatile bool has_has_value = false;
334   if (which_key == KeyType::KEY_STRING) {
335     message.key_string.SetEncoder(
336         [](ResponseInfo::StreamEncoder& key_string_encoder) -> pw::Status {
337           key_string_encoder.WriteKeyString("test");
338           return pw::OkStatus();
339         });
340   } else if (which_key == KeyType::KEY_TOKEN) {
341     message.key_token = 99999;
342   }
343   message.timestamp =
344       has_timestamp ? std::optional<uint32_t>(1663003467) : std::nullopt;
345   message.has_value = has_has_value ? std::optional<bool>(false) : std::nullopt;
346 
347   message.item_info.offset = 0x5001DBADFEEDBEE5;
348   message.item_info.size = 128;
349   message.item_info.access_level = ItemInfo::Access::WRITE;
350   ConsumeValue(encoder.Write(message));
351 }
352 
353 std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> decode_buffer;
354 pw::stream::MemoryReader reader(decode_buffer);
355 ResponseInfo::StreamDecoder decoder(reader);
356 
BasicDecode()357 PW_NO_INLINE void BasicDecode() {
358   volatile enum KeyType : uint32_t {
359     NONE = 0,
360     KEY_STRING = 1,
361     KEY_TOKEN = 2,
362   } which_key = KeyType::NONE;
363   volatile bool has_timestamp = false;
364   volatile bool has_has_value = false;
365   if (pw::Status status = decoder.Read(message); status.ok()) {
366     ConsumeValue(status);
367     has_timestamp = message.timestamp.has_value();
368     has_has_value = message.has_value.has_value();
369   }
370   ConsumeValue(which_key);
371   ConsumeValue(has_timestamp);
372   ConsumeValue(has_has_value);
373 }
374 #endif  // _PW_PROTOBUF_SIZE_REPORT_MESSAGE
375 
376 }  // namespace
377 }  // namespace pw::protobuf_size_report
378 
main()379 int main() {
380   pw::bloat::BloatThisBinary();
381   pw::protobuf_size_report::BloatWithBase();
382   pw::protobuf_size_report::BloatWithEncoder();
383   pw::protobuf_size_report::BloatWithStreamDecoder();
384   pw::protobuf_size_report::BloatWithDecoder();
385   pw::protobuf_size_report::BloatWithTableEncoder();
386   pw::protobuf_size_report::BloatWithTableDecoder();
387   pw::protobuf_size_report::BasicEncode();
388   pw::protobuf_size_report::BasicDecode();
389   return 0;
390 }
391