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