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