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