• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/util/debug_annotation_parser.h"
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <ios>
22 #include <map>
23 #include <sstream>
24 #include <string>
25 #include <utility>
26 #include <vector>
27 
28 #include "perfetto/base/status.h"
29 #include "perfetto/protozero/field.h"
30 #include "perfetto/protozero/scattered_heap_buffer.h"
31 #include "perfetto/trace_processor/ref_counted.h"
32 #include "perfetto/trace_processor/trace_blob.h"
33 #include "perfetto/trace_processor/trace_blob_view.h"
34 #include "src/protozero/test/example_proto/test_messages.pbzero.h"
35 #include "src/trace_processor/importers/proto/packet_sequence_state_builder.h"
36 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
37 #include "src/trace_processor/storage/trace_storage.h"
38 #include "src/trace_processor/test_messages.descriptor.h"
39 #include "src/trace_processor/types/trace_processor_context.h"
40 #include "src/trace_processor/util/interned_message_view.h"
41 #include "src/trace_processor/util/proto_to_args_parser.h"
42 #include "test/gtest_and_gmock.h"
43 
44 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
45 #include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
46 #include "protos/perfetto/trace/test_event.pbzero.h"
47 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
48 
49 namespace perfetto::trace_processor::util {
50 namespace {
51 
ParseDebugAnnotation(DebugAnnotationParser & parser,protozero::HeapBuffered<protos::pbzero::DebugAnnotation> & msg,ProtoToArgsParser::Delegate & delegate)52 base::Status ParseDebugAnnotation(
53     DebugAnnotationParser& parser,
54     protozero::HeapBuffered<protos::pbzero::DebugAnnotation>& msg,
55     ProtoToArgsParser::Delegate& delegate) {
56   std::vector<uint8_t> data = msg.SerializeAsArray();
57   return parser.Parse(protozero::ConstBytes{data.data(), data.size()},
58                       delegate);
59 }
60 
61 class DebugAnnotationParserTest : public ::testing::Test,
62                                   public ProtoToArgsParser::Delegate {
63  protected:
DebugAnnotationParserTest()64   DebugAnnotationParserTest() { context_.storage.reset(new TraceStorage()); }
65 
args() const66   const std::vector<std::string>& args() const { return args_; }
67 
InternMessage(uint32_t field_id,TraceBlobView message)68   void InternMessage(uint32_t field_id, TraceBlobView message) {
69     state_builder_.InternMessage(field_id, std::move(message));
70   }
71 
72  private:
73   using Key = ProtoToArgsParser::Key;
74 
AddInteger(const Key & key,int64_t value)75   void AddInteger(const Key& key, int64_t value) override {
76     std::stringstream ss;
77     ss << key.flat_key << " " << key.key << " " << value;
78     args_.push_back(ss.str());
79   }
80 
AddUnsignedInteger(const Key & key,uint64_t value)81   void AddUnsignedInteger(const Key& key, uint64_t value) override {
82     std::stringstream ss;
83     ss << key.flat_key << " " << key.key << " " << value;
84     args_.push_back(ss.str());
85   }
86 
AddString(const Key & key,const protozero::ConstChars & value)87   void AddString(const Key& key, const protozero::ConstChars& value) override {
88     std::stringstream ss;
89     ss << key.flat_key << " " << key.key << " " << value.ToStdString();
90     args_.push_back(ss.str());
91   }
92 
AddString(const Key & key,const std::string & value)93   void AddString(const Key& key, const std::string& value) override {
94     std::stringstream ss;
95     ss << key.flat_key << " " << key.key << " " << value;
96     args_.push_back(ss.str());
97   }
98 
AddDouble(const Key & key,double value)99   void AddDouble(const Key& key, double value) override {
100     std::stringstream ss;
101     ss << key.flat_key << " " << key.key << " " << value;
102     args_.push_back(ss.str());
103   }
104 
AddPointer(const Key & key,uint64_t value)105   void AddPointer(const Key& key, uint64_t value) override {
106     std::stringstream ss;
107     ss << key.flat_key << " " << key.key << " " << std::hex << value
108        << std::dec;
109     args_.push_back(ss.str());
110   }
111 
AddBoolean(const Key & key,bool value)112   void AddBoolean(const Key& key, bool value) override {
113     std::stringstream ss;
114     ss << key.flat_key << " " << key.key << " " << (value ? "true" : "false");
115     args_.push_back(ss.str());
116   }
117 
AddJson(const Key & key,const protozero::ConstChars & value)118   bool AddJson(const Key& key, const protozero::ConstChars& value) override {
119     std::stringstream ss;
120     ss << key.flat_key << " " << key.key << " " << std::hex
121        << value.ToStdString() << std::dec;
122     args_.push_back(ss.str());
123     return true;
124   }
125 
AddNull(const Key & key)126   void AddNull(const Key& key) override {
127     std::stringstream ss;
128     ss << key.flat_key << " " << key.key << " [NULL]";
129     args_.push_back(ss.str());
130   }
131 
GetArrayEntryIndex(const std::string & array_key)132   size_t GetArrayEntryIndex(const std::string& array_key) final {
133     return array_indices_[array_key];
134   }
135 
IncrementArrayEntryIndex(const std::string & array_key)136   size_t IncrementArrayEntryIndex(const std::string& array_key) final {
137     return ++array_indices_[array_key];
138   }
139 
GetInternedMessageView(uint32_t field_id,uint64_t iid)140   InternedMessageView* GetInternedMessageView(uint32_t field_id,
141                                               uint64_t iid) override {
142     return state_builder_.current_generation()->GetInternedMessageView(field_id,
143                                                                        iid);
144   }
145 
seq_state()146   PacketSequenceStateGeneration* seq_state() final {
147     return state_builder_.current_generation().get();
148   }
149 
150   std::vector<std::string> args_;
151   std::map<std::string, size_t> array_indices_;
152 
153   TraceProcessorContext context_;
154   PacketSequenceStateBuilder state_builder_{&context_};
155 };
156 
157 // This test checks that in when an array is nested inside a dict which is
158 // nested inside an array which is nested inside a dict, flat keys and non-flat
159 // keys are parsed correctly.
TEST_F(DebugAnnotationParserTest,DeeplyNestedDictsAndArrays)160 TEST_F(DebugAnnotationParserTest, DeeplyNestedDictsAndArrays) {
161   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
162 
163   msg->set_name("root");
164   auto* dict1 = msg->add_dict_entries();
165   dict1->set_name("k1");
166   auto* array1 = dict1->add_array_values();
167   auto* dict2 = array1->add_dict_entries();
168   dict2->set_name("k2");
169   auto* array2 = dict2->add_array_values();
170   array2->set_int_value(42);
171 
172   DescriptorPool pool;
173   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
174                                               kTestMessagesDescriptor.size());
175   EXPECT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
176                            << status.message();
177 
178   ProtoToArgsParser args_parser(pool);
179   DebugAnnotationParser parser(args_parser);
180 
181   status = ParseDebugAnnotation(parser, msg, *this);
182   EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
183                            << status.message();
184 
185   EXPECT_THAT(args(), testing::ElementsAre("root.k1.k2 root.k1[0].k2[0] 42"));
186 }
187 
188 // This test checks that array indexes are correctly merged across messages.
TEST_F(DebugAnnotationParserTest,MergeArrays)189 TEST_F(DebugAnnotationParserTest, MergeArrays) {
190   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg1;
191   msg1->set_name("root");
192   auto* item1 = msg1->add_array_values();
193   item1->set_int_value(1);
194 
195   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg2;
196   msg2->set_name("root");
197   auto* item2 = msg1->add_array_values();
198   item2->set_int_value(2);
199 
200   DescriptorPool pool;
201   ProtoToArgsParser args_parser(pool);
202   DebugAnnotationParser parser(args_parser);
203 
204   base::Status status = ParseDebugAnnotation(parser, msg1, *this);
205   EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
206                            << status.message();
207 
208   status = ParseDebugAnnotation(parser, msg2, *this);
209   EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
210                            << status.message();
211 
212   EXPECT_THAT(args(), testing::ElementsAre("root root[0] 1", "root root[1] 2"));
213 }
214 
215 // This test checks that nested empty dictionaries / arrays do not cause array
216 // index to be incremented.
TEST_F(DebugAnnotationParserTest,EmptyArrayIndexIsSkipped)217 TEST_F(DebugAnnotationParserTest, EmptyArrayIndexIsSkipped) {
218   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
219   msg->set_name("root");
220 
221   msg->add_array_values()->set_int_value(1);
222 
223   // Empty item.
224   msg->add_array_values();
225 
226   msg->add_array_values()->set_int_value(3);
227 
228   // Empty dict.
229   msg->add_array_values()->add_dict_entries()->set_name("key1");
230 
231   auto* nested_dict_entry = msg->add_array_values()->add_dict_entries();
232   nested_dict_entry->set_name("key2");
233   nested_dict_entry->set_string_value("value");
234 
235   msg->add_array_values()->set_int_value(5);
236 
237   DescriptorPool pool;
238   ProtoToArgsParser args_parser(pool);
239   DebugAnnotationParser parser(args_parser);
240 
241   base::Status status = ParseDebugAnnotation(parser, msg, *this);
242   EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
243                            << status.message();
244 
245   EXPECT_THAT(args(), testing::ElementsAre("root root[0] 1", "root root[1] 3",
246                                            "root.key2 root[3].key2 value",
247                                            "root root[4] 5"));
248 }
249 
TEST_F(DebugAnnotationParserTest,NestedArrays)250 TEST_F(DebugAnnotationParserTest, NestedArrays) {
251   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
252   msg->set_name("root");
253   auto* item1 = msg->add_array_values();
254   item1->add_array_values()->set_int_value(1);
255   item1->add_array_values()->set_int_value(2);
256   auto* item2 = msg->add_array_values();
257   item2->add_array_values()->set_int_value(3);
258   item2->add_array_values()->set_int_value(4);
259 
260   DescriptorPool pool;
261   ProtoToArgsParser args_parser(pool);
262   DebugAnnotationParser parser(args_parser);
263 
264   base::Status status = ParseDebugAnnotation(parser, msg, *this);
265   EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
266                            << status.message();
267 
268   EXPECT_THAT(args(),
269               testing::ElementsAre("root root[0][0] 1", "root root[0][1] 2",
270                                    "root root[1][0] 3", "root root[1][1] 4"));
271 }
272 
TEST_F(DebugAnnotationParserTest,TypedMessageInsideUntyped)273 TEST_F(DebugAnnotationParserTest, TypedMessageInsideUntyped) {
274   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
275   msg->set_name("root");
276 
277   protozero::HeapBuffered<protozero::test::protos::pbzero::EveryField> message;
278   message->set_field_string("value");
279 
280   msg->set_proto_type_name(message->GetName());
281   msg->set_proto_value(message.SerializeAsString());
282 
283   DescriptorPool pool;
284   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
285                                               kTestMessagesDescriptor.size());
286   EXPECT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
287                            << status.message();
288 
289   ProtoToArgsParser args_parser(pool);
290   DebugAnnotationParser parser(args_parser);
291 
292   status = ParseDebugAnnotation(parser, msg, *this);
293   EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
294                            << status.message();
295 
296   EXPECT_THAT(args(), testing::ElementsAre(
297                           "root.field_string root.field_string value"));
298 }
299 
TEST_F(DebugAnnotationParserTest,InternedString)300 TEST_F(DebugAnnotationParserTest, InternedString) {
301   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
302   msg->set_name("root");
303 
304   protozero::HeapBuffered<protos::pbzero::InternedString> string;
305   string->set_iid(1);
306   string->set_str("foo");
307   std::vector<uint8_t> data_serialized = string.SerializeAsArray();
308 
309   InternMessage(
310       protos::pbzero::InternedData::kDebugAnnotationStringValuesFieldNumber,
311       TraceBlobView(
312           TraceBlob::CopyFrom(data_serialized.data(), data_serialized.size())));
313 
314   msg->set_string_value_iid(1);
315 
316   DescriptorPool pool;
317   ProtoToArgsParser args_parser(pool);
318   DebugAnnotationParser parser(args_parser);
319 
320   auto status = ParseDebugAnnotation(parser, msg, *this);
321   EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
322                            << status.message();
323 
324   EXPECT_THAT(args(), testing::ElementsAre("root root foo"));
325 }
326 
327 }  // namespace
328 }  // namespace perfetto::trace_processor::util
329