xref: /aosp_15_r20/external/perfetto/src/traced/probes/ftrace/proto_translation_table_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2017 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/traced/probes/ftrace/proto_translation_table.h"
18 
19 #include "src/base/test/utils.h"
20 #include "src/traced/probes/ftrace/compact_sched.h"
21 #include "src/traced/probes/ftrace/event_info.h"
22 #include "src/traced/probes/ftrace/ftrace_procfs.h"
23 #include "test/gtest_and_gmock.h"
24 
25 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
26 #include "protos/perfetto/trace/ftrace/generic.pbzero.h"
27 
28 using testing::_;
29 using testing::AllOf;
30 using testing::AnyNumber;
31 using testing::Contains;
32 using testing::ElementsAre;
33 using testing::Eq;
34 using testing::IsNull;
35 using testing::NiceMock;
36 using testing::Pointee;
37 using testing::Return;
38 using testing::StrEq;
39 using testing::TestWithParam;
40 using testing::Values;
41 using testing::ValuesIn;
42 
43 namespace perfetto {
44 namespace {
45 using protozero::proto_utils::ProtoSchemaType;
46 
47 class MockFtraceProcfs : public FtraceProcfs {
48  public:
MockFtraceProcfs()49   MockFtraceProcfs() : FtraceProcfs("/root/") {}
50 
51   MOCK_METHOD(std::string, ReadPageHeaderFormat, (), (const, override));
52   MOCK_METHOD(std::string,
53               ReadEventFormat,
54               (const std::string& group, const std::string& name),
55               (const, override));
56 };
57 
58 class AllTranslationTableTest : public TestWithParam<const char*> {
59  public:
SetUp()60   void SetUp() override {
61     std::string path = base::GetTestDataPath(
62         "src/traced/probes/ftrace/test/data/" + std::string(GetParam()) + "/");
63     FtraceProcfs ftrace_procfs(path);
64     table_ = ProtoTranslationTable::Create(&ftrace_procfs, GetStaticEventInfo(),
65                                            GetStaticCommonFieldsInfo());
66     PERFETTO_CHECK(table_);
67   }
68 
69   std::unique_ptr<ProtoTranslationTable> table_;
70 };
71 
72 class TranslationTableCreationTest : public TestWithParam<uint16_t> {};
73 
74 const char* kDevices[] = {
75     "android_seed_N2F62_3.10.49",
76     "android_hammerhead_MRA59G_3.4.0",
77 };
78 
TEST_P(AllTranslationTableTest,Create)79 TEST_P(AllTranslationTableTest, Create) {
80   EXPECT_TRUE(table_);
81   EXPECT_TRUE(table_->GetEvent(GroupAndName("ftrace", "print")));
82   EXPECT_TRUE(table_->GetEvent(GroupAndName("sched", "sched_switch")));
83   EXPECT_TRUE(table_->GetEvent(GroupAndName("sched", "sched_wakeup")));
84   EXPECT_TRUE(table_->GetEvent(GroupAndName("ext4", "ext4_da_write_begin")));
85   for (const Event& event : table_->events()) {
86     if (!event.ftrace_event_id)
87       continue;
88     EXPECT_TRUE(event.name);
89     EXPECT_TRUE(event.group);
90     EXPECT_TRUE(event.proto_field_id);
91     for (const Field& field : event.fields) {
92       EXPECT_TRUE(field.proto_field_id);
93       EXPECT_TRUE(field.ftrace_type);
94       EXPECT_TRUE(static_cast<int>(field.proto_field_type));
95     }
96   }
97   ASSERT_LT(0u, table_->common_fields().size());
98   const Field& pid_field = table_->common_fields().at(0);
99   EXPECT_EQ(std::string(pid_field.ftrace_name), "common_pid");
100   EXPECT_EQ(pid_field.proto_field_id, 2u);
101 
102   {
103     auto event = table_->GetEvent(GroupAndName("ftrace", "print"));
104     EXPECT_TRUE(event);
105     EXPECT_EQ(std::string(event->name), "print");
106     EXPECT_EQ(std::string(event->group), "ftrace");
107 
108     EXPECT_EQ(event->fields.at(0).proto_field_type, ProtoSchemaType::kString);
109     EXPECT_EQ(event->fields.at(0).ftrace_type, kFtraceCString);
110     EXPECT_EQ(event->fields.at(0).strategy, kCStringToString);
111   }
112 }
113 
114 INSTANTIATE_TEST_SUITE_P(ByDevice, AllTranslationTableTest, ValuesIn(kDevices));
115 
TEST(TranslationTableTest,Seed)116 TEST(TranslationTableTest, Seed) {
117   std::string path = base::GetTestDataPath(
118       "src/traced/probes/ftrace/test/data/android_seed_N2F62_3.10.49/");
119   FtraceProcfs ftrace_procfs(path);
120   auto table = ProtoTranslationTable::Create(
121       &ftrace_procfs, GetStaticEventInfo(), GetStaticCommonFieldsInfo());
122   PERFETTO_CHECK(table);
123   const Field& pid_field = table->common_fields().at(0);
124   EXPECT_EQ(std::string(pid_field.ftrace_name), "common_pid");
125   EXPECT_EQ(pid_field.proto_field_id, 2u);
126   EXPECT_EQ(pid_field.ftrace_offset, 4u);
127   EXPECT_EQ(pid_field.ftrace_size, 4u);
128 
129   {
130     auto event = table->GetEvent(GroupAndName("sched", "sched_switch"));
131     EXPECT_EQ(std::string(event->name), "sched_switch");
132     EXPECT_EQ(std::string(event->group), "sched");
133     EXPECT_EQ(event->ftrace_event_id, 68ul);
134     EXPECT_EQ(event->fields.at(0).ftrace_offset, 8u);
135     EXPECT_EQ(event->fields.at(0).ftrace_size, 16u);
136   }
137 
138   {
139     auto event = table->GetEvent(GroupAndName("sched", "sched_wakeup"));
140     EXPECT_EQ(std::string(event->name), "sched_wakeup");
141     EXPECT_EQ(std::string(event->group), "sched");
142     EXPECT_EQ(event->ftrace_event_id, 70ul);
143     EXPECT_EQ(event->fields.at(0).ftrace_offset, 8u);
144     EXPECT_EQ(event->fields.at(0).ftrace_size, 16u);
145   }
146 
147   {
148     auto event = table->GetEvent(GroupAndName("ext4", "ext4_da_write_begin"));
149     EXPECT_EQ(std::string(event->name), "ext4_da_write_begin");
150     EXPECT_EQ(std::string(event->group), "ext4");
151     EXPECT_EQ(event->ftrace_event_id, 303ul);
152     EXPECT_EQ(event->fields.at(0).ftrace_offset, 8u);
153     EXPECT_EQ(event->fields.at(0).ftrace_size, 4u);
154   }
155 }
156 
TEST_P(TranslationTableCreationTest,Create)157 TEST_P(TranslationTableCreationTest, Create) {
158   MockFtraceProcfs ftrace;
159   std::vector<Field> common_fields;
160   std::vector<Event> events;
161 
162   ON_CALL(ftrace, ReadPageHeaderFormat())
163       .WillByDefault(Return(
164           R"(	field: u64 timestamp;	offset:0;	size:8;	signed:0;
165 	field: local_t commit;	offset:8;	size:)" +
166           std::to_string(GetParam()) + R"(;	signed:1;
167 	field: int overwrite;	offset:8;	size:1;	signed:1;
168 	field: char data;	offset:16;	size:4080;	signed:0;)"));
169   ON_CALL(ftrace, ReadEventFormat(_, _)).WillByDefault(Return(""));
170   ON_CALL(ftrace, ReadEventFormat("group", "foo"))
171       .WillByDefault(Return(R"(name: foo
172 ID: 42
173 format:
174 	field:unsigned short common_type;	offset:0;	size:2;	signed:0;
175 	field:int common_pid;	offset:4;	size:4;	signed:1;
176 
177 	field:char field_a[16];	offset:8;	size:16;	signed:0;
178 	field:int field_b;	offset:24;	size:4;	signed:1;
179 	field:int field_d;	offset:28;	size:4;	signed:1;
180 	field:u32 field_e;	offset:32;	size:4;	signed:0;
181 
182 print fmt: "some format")"));
183 
184   EXPECT_CALL(ftrace, ReadPageHeaderFormat()).Times(AnyNumber());
185   EXPECT_CALL(ftrace, ReadEventFormat(_, _)).Times(AnyNumber());
186 
187   {
188     events.emplace_back(Event{});
189     Event* event = &events.back();
190     event->name = "foo";
191     event->group = "group";
192     event->proto_field_id = 21;
193 
194     {
195       // We should get this field.
196       event->fields.emplace_back(Field{});
197       Field* field = &event->fields.back();
198       field->proto_field_id = 501;
199       field->proto_field_type = ProtoSchemaType::kString;
200       field->ftrace_name = "field_a";
201     }
202 
203     {
204       // We shouldn't get this field: don't know how to read int -> string.
205       event->fields.emplace_back(Field{});
206       Field* field = &event->fields.back();
207       field->proto_field_id = 502;
208       field->proto_field_type = ProtoSchemaType::kString;
209       field->ftrace_name = "field_b";
210     }
211 
212     {
213       // We shouldn't get this field: no matching field in the format file.
214       event->fields.emplace_back(Field{});
215       Field* field = &event->fields.back();
216       field->proto_field_id = 503;
217       field->proto_field_type = ProtoSchemaType::kString;
218       field->ftrace_name = "field_c";
219     }
220 
221     {
222       // We should get this field.
223       event->fields.emplace_back(Field{});
224       Field* field = &event->fields.back();
225       field->proto_field_id = 504;
226       field->proto_field_type = ProtoSchemaType::kUint64;
227       field->ftrace_name = "field_e";
228     }
229   }
230 
231   {
232     events.emplace_back(Event{});
233     Event* event = &events.back();
234     event->name = "bar";
235     event->group = "group";
236     event->proto_field_id = 22;
237   }
238 
239   auto table = ProtoTranslationTable::Create(&ftrace, std::move(events),
240                                              std::move(common_fields));
241   PERFETTO_CHECK(table);
242   EXPECT_EQ(table->largest_id(), 42ul);
243   EXPECT_EQ(table->EventToFtraceId(GroupAndName("group", "foo")), 42ul);
244   EXPECT_EQ(table->EventToFtraceId(GroupAndName("group", "bar")), 0ul);
245   EXPECT_FALSE(table->GetEventById(43ul));
246   ASSERT_TRUE(table->GetEventById(42ul));
247   EXPECT_EQ(table->ftrace_page_header_spec().timestamp.size, 8);
248   EXPECT_EQ(table->ftrace_page_header_spec().size.size, GetParam());
249   EXPECT_EQ(table->ftrace_page_header_spec().overwrite.size, 1);
250   auto event = table->GetEventById(42);
251   EXPECT_EQ(event->ftrace_event_id, 42ul);
252   EXPECT_EQ(event->proto_field_id, 21ul);
253   EXPECT_EQ(event->size, 36u);
254   EXPECT_EQ(std::string(event->name), "foo");
255   EXPECT_EQ(std::string(event->group), "group");
256 
257   ASSERT_EQ(event->fields.size(), 2ul);
258   auto field_a = event->fields.at(0);
259   EXPECT_EQ(field_a.proto_field_id, 501ul);
260   EXPECT_EQ(field_a.strategy, kFixedCStringToString);
261 
262   auto field_e = event->fields.at(1);
263   EXPECT_EQ(field_e.proto_field_id, 504ul);
264   EXPECT_EQ(field_e.strategy, kUint32ToUint64);
265 }
266 
267 INSTANTIATE_TEST_SUITE_P(BySize, TranslationTableCreationTest, Values(4, 8));
268 
TEST(TranslationTableTest,CompactSchedFormatParsingWalleyeData)269 TEST(TranslationTableTest, CompactSchedFormatParsingWalleyeData) {
270   std::string path = base::GetTestDataPath(
271       "src/traced/probes/ftrace/test/data/"
272       "android_walleye_OPM5.171019.017.A1_4.4.88/");
273   FtraceProcfs ftrace_procfs(path);
274   auto table = ProtoTranslationTable::Create(
275       &ftrace_procfs, GetStaticEventInfo(), GetStaticCommonFieldsInfo());
276   PERFETTO_CHECK(table);
277   const CompactSchedEventFormat& format = table->compact_sched_format();
278 
279   // Format matches compile-time assumptions.
280   ASSERT_TRUE(format.format_valid);
281 
282   // Check exact sched_switch format (note: 64 bit long prev_state).
283   EXPECT_EQ(47u, format.sched_switch.event_id);
284   EXPECT_EQ(64u, format.sched_switch.size);
285   EXPECT_EQ(56u, format.sched_switch.next_pid_offset);
286   EXPECT_EQ(FtraceFieldType::kFtracePid32, format.sched_switch.next_pid_type);
287   EXPECT_EQ(60u, format.sched_switch.next_prio_offset);
288   EXPECT_EQ(FtraceFieldType::kFtraceInt32, format.sched_switch.next_prio_type);
289   EXPECT_EQ(32u, format.sched_switch.prev_state_offset);
290   EXPECT_EQ(FtraceFieldType::kFtraceInt64, format.sched_switch.prev_state_type);
291   EXPECT_EQ(40u, format.sched_switch.next_comm_offset);
292 
293   // Check exact sched_waking format.
294   EXPECT_EQ(44u, format.sched_waking.event_id);
295   EXPECT_EQ(40u, format.sched_waking.size);
296   EXPECT_EQ(24u, format.sched_waking.pid_offset);
297   EXPECT_EQ(FtraceFieldType::kFtracePid32, format.sched_waking.pid_type);
298   EXPECT_EQ(36u, format.sched_waking.target_cpu_offset);
299   EXPECT_EQ(FtraceFieldType::kFtraceInt32, format.sched_waking.target_cpu_type);
300   EXPECT_EQ(28u, format.sched_waking.prio_offset);
301   EXPECT_EQ(FtraceFieldType::kFtraceInt32, format.sched_waking.prio_type);
302   EXPECT_EQ(8u, format.sched_waking.comm_offset);
303 }
304 
TEST(TranslationTableTest,CompactSchedFormatParsingSeedData)305 TEST(TranslationTableTest, CompactSchedFormatParsingSeedData) {
306   std::string path =
307       "src/traced/probes/ftrace/test/data/android_seed_N2F62_3.10.49/";
308   FtraceProcfs ftrace_procfs(path);
309   auto table = ProtoTranslationTable::Create(
310       &ftrace_procfs, GetStaticEventInfo(), GetStaticCommonFieldsInfo());
311   PERFETTO_CHECK(table);
312   const CompactSchedEventFormat& format = table->compact_sched_format();
313 
314   // We consider the entire format invalid as there's no sched_waking event
315   // available. This is a simplifying assumption. We could instead look at each
316   // event independently (and in this case, sched_switch does match compile-time
317   // assumptions).
318   ASSERT_FALSE(format.format_valid);
319 }
320 
TEST(TranslationTableTest,InferFtraceType)321 TEST(TranslationTableTest, InferFtraceType) {
322   FtraceFieldType type;
323 
324   ASSERT_TRUE(InferFtraceType("char foo[16]", 16, false, &type));
325   EXPECT_EQ(type, kFtraceFixedCString);
326 
327   ASSERT_TRUE(InferFtraceType("char comm[TASK_COMM_LEN]", 16, false, &type));
328   EXPECT_EQ(type, kFtraceFixedCString);
329 
330   ASSERT_TRUE(InferFtraceType("char identifier22[16]", 16, false, &type));
331   EXPECT_EQ(type, kFtraceFixedCString);
332 
333   EXPECT_FALSE(InferFtraceType("char 2invalid[16]", 16, false, &type));
334 
335   ASSERT_TRUE(InferFtraceType("char[] foo", 8, false, &type));
336   EXPECT_EQ(type, kFtraceStringPtr);
337 
338   ASSERT_TRUE(InferFtraceType("char * foo", 8, false, &type));
339   EXPECT_EQ(type, kFtraceStringPtr);
340 
341   ASSERT_TRUE(InferFtraceType("char foo[64]", 64, false, &type));
342   EXPECT_EQ(type, kFtraceFixedCString);
343 
344   ASSERT_TRUE(InferFtraceType("u32 foo", 4, false, &type));
345   EXPECT_EQ(type, kFtraceUint32);
346 
347   ASSERT_TRUE(InferFtraceType("i_ino foo", 4, false, &type));
348   ASSERT_EQ(type, kFtraceInode32);
349 
350   ASSERT_TRUE(InferFtraceType("i_ino foo", 8, false, &type));
351   ASSERT_EQ(type, kFtraceInode64);
352 
353   ASSERT_TRUE(InferFtraceType("ino_t foo", 4, false, &type));
354   ASSERT_EQ(type, kFtraceInode32);
355 
356   ASSERT_TRUE(InferFtraceType("ino_t foo", 8, false, &type));
357   ASSERT_EQ(type, kFtraceInode64);
358 
359   ASSERT_TRUE(InferFtraceType("dev_t foo", 4, false, &type));
360   ASSERT_EQ(type, kFtraceDevId32);
361 
362   ASSERT_TRUE(InferFtraceType("dev_t foo", 8, false, &type));
363   ASSERT_EQ(type, kFtraceDevId64);
364 
365   ASSERT_TRUE(InferFtraceType("pid_t foo", 4, false, &type));
366   ASSERT_EQ(type, kFtracePid32);
367 
368   ASSERT_TRUE(InferFtraceType("int common_pid", 4, false, &type));
369   ASSERT_EQ(type, kFtraceCommonPid32);
370 
371   ASSERT_TRUE(InferFtraceType("char foo", 1, true, &type));
372   ASSERT_EQ(type, kFtraceInt8);
373 
374   ASSERT_TRUE(InferFtraceType("__data_loc char[] foo", 4, false, &type));
375   ASSERT_EQ(type, kFtraceDataLoc);
376   ASSERT_FALSE(InferFtraceType("__data_loc char[] foo", 8, false, &type));
377 
378   ASSERT_TRUE(InferFtraceType("unsigned long args[6]", 24, true, &type));
379   ASSERT_EQ(type, kFtraceUint32);
380   ASSERT_TRUE(InferFtraceType("unsigned long args[6]", 48, true, &type));
381   ASSERT_EQ(type, kFtraceUint64);
382   ASSERT_FALSE(InferFtraceType("unsigned long args[6]", 96, true, &type));
383 
384   EXPECT_FALSE(InferFtraceType("foo", 64, false, &type));
385 }
386 
TEST(TranslationTableTest,Getters)387 TEST(TranslationTableTest, Getters) {
388   MockFtraceProcfs ftrace;
389   std::vector<Field> common_fields;
390   std::vector<Event> events;
391 
392   {
393     Event event{};
394     event.name = "foo";
395     event.group = "group_one";
396     event.ftrace_event_id = 1;
397     events.push_back(event);
398   }
399 
400   {
401     Event event{};
402     event.name = "bar";
403     event.group = "group_one";
404     event.ftrace_event_id = 2;
405     events.push_back(event);
406   }
407 
408   {
409     Event event{};
410     event.name = "baz";
411     event.group = "group_two";
412     event.ftrace_event_id = 100;
413     events.push_back(event);
414   }
415 
416   ProtoTranslationTable table(
417       &ftrace, events, std::move(common_fields),
418       ProtoTranslationTable::DefaultPageHeaderSpecForTesting(),
419       InvalidCompactSchedEventFormatForTesting(), PrintkMap());
420 
421   EXPECT_EQ(table.largest_id(), 100ul);
422   EXPECT_EQ(table.EventToFtraceId(GroupAndName("group_one", "foo")), 1ul);
423   EXPECT_EQ(table.EventToFtraceId(GroupAndName("group_two", "baz")), 100ul);
424   EXPECT_EQ(table.EventToFtraceId(GroupAndName("group_one", "no_such_event")),
425             0ul);
426   EXPECT_EQ(table.GetEventById(1)->name, "foo");
427   EXPECT_EQ(table.GetEventById(3), nullptr);
428   EXPECT_EQ(table.GetEventById(200), nullptr);
429   EXPECT_EQ(table.GetEventById(0), nullptr);
430   EXPECT_EQ(table.GetEvent(GroupAndName("group_one", "foo"))->ftrace_event_id,
431             1u);
432   EXPECT_THAT(*table.GetEventsByGroup("group_one"),
433               Contains(testing::Field(&Event::name, "foo")));
434   EXPECT_THAT(*table.GetEventsByGroup("group_one"),
435               Contains(testing::Field(&Event::name, "bar")));
436   EXPECT_THAT(*table.GetEventsByGroup("group_two"),
437               Contains(testing::Field(&Event::name, "baz")));
438   EXPECT_THAT(table.GetEventsByGroup("group_three"), IsNull());
439 }
440 
TEST(TranslationTableTest,Generic)441 TEST(TranslationTableTest, Generic) {
442   MockFtraceProcfs ftrace;
443   std::vector<Field> common_fields;
444   std::vector<Event> events;
445 
446   ON_CALL(ftrace, ReadPageHeaderFormat())
447       .WillByDefault(Return(
448           R"(	field: u64 timestamp;	offset:0;	size:8;	signed:0;
449 	field: local_t commit;	offset:8;	size:4;	signed:1;
450 	field: int overwrite;	offset:8;	size:1;	signed:1;
451 	field: char data;	offset:16;	size:4080;	signed:0;)"));
452   ON_CALL(ftrace, ReadEventFormat(_, _)).WillByDefault(Return(""));
453   ON_CALL(ftrace, ReadEventFormat("group", "foo"))
454       .WillByDefault(Return(R"(name: foo
455 ID: 42
456 format:
457 	field:unsigned short common_type;	offset:0;	size:2;	signed:0;
458 	field:int common_pid;	offset:4;	size:4;	signed:1;
459 
460 	field:char field_a[16];	offset:8;	size:16;	signed:0;
461 	field:bool field_b;	offset:24;	size:1;	signed:0;
462 	field:int field_c;	offset:25;	size:4;	signed:1;
463 	field:u32 field_d;	offset:33;	size:4;	signed:0;
464 
465 print fmt: "some format")"));
466 
467   EXPECT_CALL(ftrace, ReadPageHeaderFormat()).Times(AnyNumber());
468   EXPECT_CALL(ftrace, ReadEventFormat(_, _)).Times(AnyNumber());
469 
470   auto table = ProtoTranslationTable::Create(&ftrace, std::move(events),
471                                              std::move(common_fields));
472   PERFETTO_CHECK(table);
473   EXPECT_EQ(table->largest_id(), 0ul);
474   GroupAndName group_and_name("group", "foo");
475   const Event* e = table->GetOrCreateEvent(group_and_name);
476   EXPECT_EQ(table->largest_id(), 42ul);
477   EXPECT_EQ(table->EventToFtraceId(group_and_name), 42ul);
478 
479   // Check getters
480   EXPECT_EQ(static_cast<int>(table->GetEventById(42)->proto_field_id),
481             protos::pbzero::FtraceEvent::kGenericFieldNumber);
482   EXPECT_EQ(static_cast<int>(table->GetEvent(group_and_name)->proto_field_id),
483             protos::pbzero::FtraceEvent::kGenericFieldNumber);
484   EXPECT_EQ(table->GetEventsByGroup("group")->front()->name,
485             group_and_name.name());
486 
487   EXPECT_EQ(e->fields.size(), 4ul);
488   const std::vector<Field>& fields = e->fields;
489   // Check string field
490   const auto& str_field = fields[0];
491   EXPECT_STREQ(str_field.ftrace_name, "field_a");
492   EXPECT_EQ(static_cast<int>(str_field.proto_field_id),
493             protos::pbzero::GenericFtraceEvent::Field::kStrValueFieldNumber);
494   EXPECT_EQ(str_field.proto_field_type, ProtoSchemaType::kString);
495   EXPECT_EQ(str_field.ftrace_type, kFtraceFixedCString);
496   EXPECT_EQ(str_field.ftrace_size, 16);
497   EXPECT_EQ(str_field.ftrace_offset, 8);
498 
499   // Check bool field
500   const auto& bool_field = fields[1];
501   EXPECT_STREQ(bool_field.ftrace_name, "field_b");
502   EXPECT_EQ(static_cast<int>(bool_field.proto_field_id),
503             protos::pbzero::GenericFtraceEvent::Field::kUintValueFieldNumber);
504   EXPECT_EQ(bool_field.proto_field_type, ProtoSchemaType::kUint64);
505   EXPECT_EQ(bool_field.ftrace_type, kFtraceBool);
506   EXPECT_EQ(bool_field.ftrace_size, 1);
507   EXPECT_EQ(bool_field.ftrace_offset, 24);
508 
509   // Check int field
510   const auto& int_field = fields[2];
511   EXPECT_STREQ(int_field.ftrace_name, "field_c");
512   EXPECT_EQ(static_cast<int>(int_field.proto_field_id),
513             protos::pbzero::GenericFtraceEvent::Field::kIntValueFieldNumber);
514   EXPECT_EQ(int_field.proto_field_type, ProtoSchemaType::kInt64);
515   EXPECT_EQ(int_field.ftrace_type, kFtraceInt32);
516   EXPECT_EQ(int_field.ftrace_size, 4);
517   EXPECT_EQ(int_field.ftrace_offset, 25);
518 
519   // Check uint field
520   const auto& uint_field = fields[3];
521   EXPECT_STREQ(uint_field.ftrace_name, "field_d");
522   EXPECT_EQ(static_cast<int>(uint_field.proto_field_id),
523             protos::pbzero::GenericFtraceEvent::Field::kUintValueFieldNumber);
524   EXPECT_EQ(uint_field.proto_field_type, ProtoSchemaType::kUint64);
525   EXPECT_EQ(uint_field.ftrace_type, kFtraceUint32);
526   EXPECT_EQ(uint_field.ftrace_size, 4);
527   EXPECT_EQ(uint_field.ftrace_offset, 33);
528 }
529 
TEST(EventFilterTest,EnableEventsFrom)530 TEST(EventFilterTest, EnableEventsFrom) {
531   EventFilter filter;
532   filter.AddEnabledEvent(1);
533   filter.AddEnabledEvent(17);
534 
535   EventFilter or_filter;
536   or_filter.AddEnabledEvent(4);
537   or_filter.AddEnabledEvent(17);
538 
539   filter.EnableEventsFrom(or_filter);
540   EXPECT_TRUE(filter.IsEventEnabled(4));
541   EXPECT_TRUE(filter.IsEventEnabled(17));
542   EXPECT_TRUE(filter.IsEventEnabled(1));
543   EXPECT_FALSE(filter.IsEventEnabled(2));
544 
545   EventFilter empty_filter;
546   filter.EnableEventsFrom(empty_filter);
547   EXPECT_TRUE(filter.IsEventEnabled(4));
548   EXPECT_TRUE(filter.IsEventEnabled(17));
549   EXPECT_TRUE(filter.IsEventEnabled(1));
550 
551   empty_filter.EnableEventsFrom(filter);
552   EXPECT_TRUE(empty_filter.IsEventEnabled(4));
553   EXPECT_TRUE(empty_filter.IsEventEnabled(17));
554   EXPECT_TRUE(empty_filter.IsEventEnabled(1));
555 }
556 
TEST(TranslationTableTest,FuncgraphEvents)557 TEST(TranslationTableTest, FuncgraphEvents) {
558   std::string path =
559       base::GetTestDataPath("src/traced/probes/ftrace/test/data/synthetic/");
560   FtraceProcfs ftrace_procfs(path);
561   auto table = ProtoTranslationTable::Create(
562       &ftrace_procfs, GetStaticEventInfo(), GetStaticCommonFieldsInfo());
563   PERFETTO_CHECK(table);
564 
565   {
566     auto* event = table->GetEvent(GroupAndName("ftrace", "funcgraph_entry"));
567     EXPECT_EQ(std::string(event->name), "funcgraph_entry");
568     EXPECT_EQ(std::string(event->group), "ftrace");
569 
570     // field:unsigned long func;  offset:8;   size:8;  signed:0;
571     // field:int depth;           offset:16;  size:4;  signed:1;
572     ASSERT_EQ(event->fields.size(), 2u);
573 
574     // note: fields in struct are ordered as in the proto, not the format file
575     EXPECT_THAT(
576         event->fields,
577         Contains(
578             AllOf(testing::Field(&Field::ftrace_name, StrEq("func")),
579                   testing::Field(&Field::ftrace_offset, Eq(8u)),
580                   testing::Field(&Field::ftrace_type, kFtraceSymAddr64),
581                   testing::Field(&Field::strategy, kFtraceSymAddr64ToUint64))));
582   }
583   {
584     auto* event = table->GetEvent(GroupAndName("ftrace", "funcgraph_exit"));
585     EXPECT_EQ(std::string(event->name), "funcgraph_exit");
586     EXPECT_EQ(std::string(event->group), "ftrace");
587 
588     // field:unsigned long func;           offset:8;   size:8;  signed:0;
589     // field:int depth;                    offset:16;  size:4;  signed:1;
590     // field:unsigned int overrun;         offset:20;  size:4;  signed:0;
591     // field:unsigned long long calltime;  offset:24;  size:8;  signed:0;
592     // field:unsigned long long rettime;   offset:32;  size:8;  signed:0;
593     ASSERT_EQ(event->fields.size(), 5u);
594     // note: fields in struct are ordered as in the proto, not the format file
595     EXPECT_THAT(
596         event->fields,
597         Contains(
598             AllOf(testing::Field(&Field::ftrace_name, StrEq("func")),
599                   testing::Field(&Field::ftrace_offset, Eq(8u)),
600                   testing::Field(&Field::ftrace_type, kFtraceSymAddr64),
601                   testing::Field(&Field::strategy, kFtraceSymAddr64ToUint64))));
602   }
603 }
604 
TEST(TranslationTableTest,CreateRemoveKprobeEvent)605 TEST(TranslationTableTest, CreateRemoveKprobeEvent) {
606   NiceMock<MockFtraceProcfs> ftrace;
607   ON_CALL(ftrace, ReadEventFormat(_, _)).WillByDefault(Return(""));
608   ON_CALL(ftrace, ReadPageHeaderFormat())
609       .WillByDefault(Return(
610           R"(	field: u64 timestamp;	offset:0;	size:8;	signed:0;
611 	field: local_t commit;	offset:8;	size:4;	signed:1;
612 	field: int overwrite;	offset:8;	size:1;	signed:1;
613 	field: char data;	offset:16;	size:4080;	signed:0;)"));
614   auto table = ProtoTranslationTable::Create(&ftrace, GetStaticEventInfo(),
615                                              GetStaticCommonFieldsInfo());
616   PERFETTO_CHECK(table);
617 
618   EXPECT_CALL(ftrace,
619               ReadEventFormat("perfetto_kprobe", "fuse_file_write_iter"))
620       .WillOnce(Return(R"format(name: fuse_file_write_iter
621 ID: 1535
622 format:
623         field:unsigned short common_type;       offset:0;       size:2; signed:0;
624         field:unsigned char common_flags;       offset:2;       size:1; signed:0;
625         field:unsigned char common_preempt_count;       offset:3;       size:1; signed:0;
626         field:int common_pid;   offset:4;       size:4; signed:1;
627 
628         field:unsigned long __probe_ip; offset:8;       size:8; signed:0;
629 
630 print fmt: "(%lx)", REC->__probe_ip
631 )format"));
632   const Event* event = table->GetOrCreateKprobeEvent(
633       {"perfetto_kprobe", "fuse_file_write_iter"});
634   ASSERT_NE(event, nullptr);
635   EXPECT_EQ(event->ftrace_event_id, 1535u);
636   EXPECT_EQ(table->GetEventByName("fuse_file_write_iter"), event);
637   EXPECT_THAT(table->GetEventsByGroup("perfetto_kprobe"),
638               Pointee(ElementsAre(event)));
639   EXPECT_EQ(table->GetEventById(1535), event);
640 
641   table->RemoveEvent({"perfetto_kprobe", "fuse_file_write_iter"});
642   EXPECT_EQ(table->GetEventByName("fuse_file_write_iter"), nullptr);
643   EXPECT_EQ(table->GetEventsByGroup("perfetto_kprobe"), nullptr);
644   EXPECT_EQ(table->GetEventById(1535), nullptr);
645 
646   EXPECT_CALL(ftrace,
647               ReadEventFormat("perfetto_kprobe", "fuse_file_write_iter"))
648       .WillOnce(Return(R"format(name: fuse_file_write_iter
649 ID: 1536
650 format:
651         field:unsigned short common_type;       offset:0;       size:2; signed:0;
652         field:unsigned char common_flags;       offset:2;       size:1; signed:0;
653         field:unsigned char common_preempt_count;       offset:3;       size:1; signed:0;
654         field:int common_pid;   offset:4;       size:4; signed:1;
655 
656         field:unsigned long __probe_ip; offset:8;       size:8; signed:0;
657 
658 print fmt: "(%lx)", REC->__probe_ip
659 )format"));
660   event = table->GetOrCreateKprobeEvent(
661       {"perfetto_kprobe", "fuse_file_write_iter"});
662   ASSERT_NE(event, nullptr);
663   EXPECT_EQ(event->ftrace_event_id, 1536u);
664   EXPECT_EQ(table->GetEventByName("fuse_file_write_iter"), event);
665   EXPECT_THAT(table->GetEventsByGroup("perfetto_kprobe"),
666               Pointee(ElementsAre(event)));
667   EXPECT_EQ(table->GetEventById(1536), event);
668 }
669 
670 }  // namespace
671 }  // namespace perfetto
672