| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "src/traced/probes/ftrace/proto_translation_table.h" |
| |
| #include "src/base/test/gtest_test_suite.h" |
| #include "src/base/test/utils.h" |
| #include "src/traced/probes/ftrace/compact_sched.h" |
| #include "src/traced/probes/ftrace/event_info.h" |
| #include "src/traced/probes/ftrace/ftrace_procfs.h" |
| #include "test/gtest_and_gmock.h" |
| |
| #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h" |
| #include "protos/perfetto/trace/ftrace/generic.pbzero.h" |
| |
| using testing::_; |
| using testing::AllOf; |
| using testing::AnyNumber; |
| using testing::Contains; |
| using testing::Eq; |
| using testing::IsNull; |
| using testing::Pointee; |
| using testing::Return; |
| using testing::StrEq; |
| using testing::TestWithParam; |
| using testing::Values; |
| using testing::ValuesIn; |
| |
| namespace perfetto { |
| namespace { |
| using protozero::proto_utils::ProtoSchemaType; |
| |
| class MockFtraceProcfs : public FtraceProcfs { |
| public: |
| MockFtraceProcfs() : FtraceProcfs("/root/") {} |
| |
| MOCK_METHOD(std::string, ReadPageHeaderFormat, (), (const, override)); |
| MOCK_METHOD(std::string, |
| ReadEventFormat, |
| (const std::string& group, const std::string& name), |
| (const, override)); |
| }; |
| |
| class AllTranslationTableTest : public TestWithParam<const char*> { |
| public: |
| void SetUp() override { |
| std::string path = base::GetTestDataPath( |
| "src/traced/probes/ftrace/test/data/" + std::string(GetParam()) + "/"); |
| FtraceProcfs ftrace_procfs(path); |
| table_ = ProtoTranslationTable::Create(&ftrace_procfs, GetStaticEventInfo(), |
| GetStaticCommonFieldsInfo()); |
| PERFETTO_CHECK(table_); |
| } |
| |
| std::unique_ptr<ProtoTranslationTable> table_; |
| }; |
| |
| class TranslationTableCreationTest : public TestWithParam<uint16_t> {}; |
| |
| const char* kDevices[] = { |
| "android_seed_N2F62_3.10.49", |
| "android_hammerhead_MRA59G_3.4.0", |
| }; |
| |
| TEST_P(AllTranslationTableTest, Create) { |
| EXPECT_TRUE(table_); |
| EXPECT_TRUE(table_->GetEvent(GroupAndName("ftrace", "print"))); |
| EXPECT_TRUE(table_->GetEvent(GroupAndName("sched", "sched_switch"))); |
| EXPECT_TRUE(table_->GetEvent(GroupAndName("sched", "sched_wakeup"))); |
| EXPECT_TRUE(table_->GetEvent(GroupAndName("ext4", "ext4_da_write_begin"))); |
| for (const Event& event : table_->events()) { |
| if (!event.ftrace_event_id) |
| continue; |
| EXPECT_TRUE(event.name); |
| EXPECT_TRUE(event.group); |
| EXPECT_TRUE(event.proto_field_id); |
| for (const Field& field : event.fields) { |
| EXPECT_TRUE(field.proto_field_id); |
| EXPECT_TRUE(field.ftrace_type); |
| EXPECT_TRUE(static_cast<int>(field.proto_field_type)); |
| } |
| } |
| ASSERT_LT(0u, table_->common_fields().size()); |
| const Field& pid_field = table_->common_fields().at(0); |
| EXPECT_EQ(std::string(pid_field.ftrace_name), "common_pid"); |
| EXPECT_EQ(pid_field.proto_field_id, 2u); |
| |
| { |
| auto event = table_->GetEvent(GroupAndName("ftrace", "print")); |
| EXPECT_TRUE(event); |
| EXPECT_EQ(std::string(event->name), "print"); |
| EXPECT_EQ(std::string(event->group), "ftrace"); |
| |
| EXPECT_EQ(event->fields.at(0).proto_field_type, ProtoSchemaType::kString); |
| EXPECT_EQ(event->fields.at(0).ftrace_type, kFtraceCString); |
| EXPECT_EQ(event->fields.at(0).strategy, kCStringToString); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(ByDevice, AllTranslationTableTest, ValuesIn(kDevices)); |
| |
| TEST(TranslationTableTest, Seed) { |
| std::string path = base::GetTestDataPath( |
| "src/traced/probes/ftrace/test/data/android_seed_N2F62_3.10.49/"); |
| FtraceProcfs ftrace_procfs(path); |
| auto table = ProtoTranslationTable::Create( |
| &ftrace_procfs, GetStaticEventInfo(), GetStaticCommonFieldsInfo()); |
| PERFETTO_CHECK(table); |
| const Field& pid_field = table->common_fields().at(0); |
| EXPECT_EQ(std::string(pid_field.ftrace_name), "common_pid"); |
| EXPECT_EQ(pid_field.proto_field_id, 2u); |
| EXPECT_EQ(pid_field.ftrace_offset, 4u); |
| EXPECT_EQ(pid_field.ftrace_size, 4u); |
| |
| { |
| auto event = table->GetEvent(GroupAndName("sched", "sched_switch")); |
| EXPECT_EQ(std::string(event->name), "sched_switch"); |
| EXPECT_EQ(std::string(event->group), "sched"); |
| EXPECT_EQ(event->ftrace_event_id, 68ul); |
| EXPECT_EQ(event->fields.at(0).ftrace_offset, 8u); |
| EXPECT_EQ(event->fields.at(0).ftrace_size, 16u); |
| } |
| |
| { |
| auto event = table->GetEvent(GroupAndName("sched", "sched_wakeup")); |
| EXPECT_EQ(std::string(event->name), "sched_wakeup"); |
| EXPECT_EQ(std::string(event->group), "sched"); |
| EXPECT_EQ(event->ftrace_event_id, 70ul); |
| EXPECT_EQ(event->fields.at(0).ftrace_offset, 8u); |
| EXPECT_EQ(event->fields.at(0).ftrace_size, 16u); |
| } |
| |
| { |
| auto event = table->GetEvent(GroupAndName("ext4", "ext4_da_write_begin")); |
| EXPECT_EQ(std::string(event->name), "ext4_da_write_begin"); |
| EXPECT_EQ(std::string(event->group), "ext4"); |
| EXPECT_EQ(event->ftrace_event_id, 303ul); |
| EXPECT_EQ(event->fields.at(0).ftrace_offset, 8u); |
| EXPECT_EQ(event->fields.at(0).ftrace_size, 4u); |
| } |
| } |
| |
| TEST_P(TranslationTableCreationTest, Create) { |
| MockFtraceProcfs ftrace; |
| std::vector<Field> common_fields; |
| std::vector<Event> events; |
| |
| ON_CALL(ftrace, ReadPageHeaderFormat()) |
| .WillByDefault(Return( |
| R"( field: u64 timestamp; offset:0; size:8; signed:0; |
| field: local_t commit; offset:8; size:)" + |
| std::to_string(GetParam()) + R"(; signed:1; |
| field: int overwrite; offset:8; size:1; signed:1; |
| field: char data; offset:16; size:4080; signed:0;)")); |
| ON_CALL(ftrace, ReadEventFormat(_, _)).WillByDefault(Return("")); |
| ON_CALL(ftrace, ReadEventFormat("group", "foo")) |
| .WillByDefault(Return(R"(name: foo |
| ID: 42 |
| format: |
| field:unsigned short common_type; offset:0; size:2; signed:0; |
| field:int common_pid; offset:4; size:4; signed:1; |
| |
| field:char field_a[16]; offset:8; size:16; signed:0; |
| field:int field_b; offset:24; size:4; signed:1; |
| field:int field_d; offset:28; size:4; signed:1; |
| field:u32 field_e; offset:32; size:4; signed:0; |
| |
| print fmt: "some format")")); |
| |
| EXPECT_CALL(ftrace, ReadPageHeaderFormat()).Times(AnyNumber()); |
| EXPECT_CALL(ftrace, ReadEventFormat(_, _)).Times(AnyNumber()); |
| |
| { |
| events.emplace_back(Event{}); |
| Event* event = &events.back(); |
| event->name = "foo"; |
| event->group = "group"; |
| event->proto_field_id = 21; |
| |
| { |
| // We should get this field. |
| event->fields.emplace_back(Field{}); |
| Field* field = &event->fields.back(); |
| field->proto_field_id = 501; |
| field->proto_field_type = ProtoSchemaType::kString; |
| field->ftrace_name = "field_a"; |
| } |
| |
| { |
| // We shouldn't get this field: don't know how to read int -> string. |
| event->fields.emplace_back(Field{}); |
| Field* field = &event->fields.back(); |
| field->proto_field_id = 502; |
| field->proto_field_type = ProtoSchemaType::kString; |
| field->ftrace_name = "field_b"; |
| } |
| |
| { |
| // We shouldn't get this field: no matching field in the format file. |
| event->fields.emplace_back(Field{}); |
| Field* field = &event->fields.back(); |
| field->proto_field_id = 503; |
| field->proto_field_type = ProtoSchemaType::kString; |
| field->ftrace_name = "field_c"; |
| } |
| |
| { |
| // We should get this field. |
| event->fields.emplace_back(Field{}); |
| Field* field = &event->fields.back(); |
| field->proto_field_id = 504; |
| field->proto_field_type = ProtoSchemaType::kUint64; |
| field->ftrace_name = "field_e"; |
| } |
| } |
| |
| { |
| events.emplace_back(Event{}); |
| Event* event = &events.back(); |
| event->name = "bar"; |
| event->group = "group"; |
| event->proto_field_id = 22; |
| } |
| |
| auto table = ProtoTranslationTable::Create(&ftrace, std::move(events), |
| std::move(common_fields)); |
| PERFETTO_CHECK(table); |
| EXPECT_EQ(table->largest_id(), 42ul); |
| EXPECT_EQ(table->EventToFtraceId(GroupAndName("group", "foo")), 42ul); |
| EXPECT_EQ(table->EventToFtraceId(GroupAndName("group", "bar")), 0ul); |
| EXPECT_FALSE(table->GetEventById(43ul)); |
| ASSERT_TRUE(table->GetEventById(42ul)); |
| EXPECT_EQ(table->ftrace_page_header_spec().timestamp.size, 8); |
| EXPECT_EQ(table->ftrace_page_header_spec().size.size, GetParam()); |
| EXPECT_EQ(table->ftrace_page_header_spec().overwrite.size, 1); |
| auto event = table->GetEventById(42); |
| EXPECT_EQ(event->ftrace_event_id, 42ul); |
| EXPECT_EQ(event->proto_field_id, 21ul); |
| EXPECT_EQ(event->size, 36u); |
| EXPECT_EQ(std::string(event->name), "foo"); |
| EXPECT_EQ(std::string(event->group), "group"); |
| |
| ASSERT_EQ(event->fields.size(), 2ul); |
| auto field_a = event->fields.at(0); |
| EXPECT_EQ(field_a.proto_field_id, 501ul); |
| EXPECT_EQ(field_a.strategy, kFixedCStringToString); |
| |
| auto field_e = event->fields.at(1); |
| EXPECT_EQ(field_e.proto_field_id, 504ul); |
| EXPECT_EQ(field_e.strategy, kUint32ToUint64); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(BySize, TranslationTableCreationTest, Values(4, 8)); |
| |
| TEST(TranslationTableTest, CompactSchedFormatParsingWalleyeData) { |
| std::string path = base::GetTestDataPath( |
| "src/traced/probes/ftrace/test/data/" |
| "android_walleye_OPM5.171019.017.A1_4.4.88/"); |
| FtraceProcfs ftrace_procfs(path); |
| auto table = ProtoTranslationTable::Create( |
| &ftrace_procfs, GetStaticEventInfo(), GetStaticCommonFieldsInfo()); |
| PERFETTO_CHECK(table); |
| const CompactSchedEventFormat& format = table->compact_sched_format(); |
| |
| // Format matches compile-time assumptions. |
| ASSERT_TRUE(format.format_valid); |
| |
| // Check exact sched_switch format (note: 64 bit long prev_state). |
| EXPECT_EQ(47u, format.sched_switch.event_id); |
| EXPECT_EQ(64u, format.sched_switch.size); |
| EXPECT_EQ(56u, format.sched_switch.next_pid_offset); |
| EXPECT_EQ(FtraceFieldType::kFtracePid32, format.sched_switch.next_pid_type); |
| EXPECT_EQ(60u, format.sched_switch.next_prio_offset); |
| EXPECT_EQ(FtraceFieldType::kFtraceInt32, format.sched_switch.next_prio_type); |
| EXPECT_EQ(32u, format.sched_switch.prev_state_offset); |
| EXPECT_EQ(FtraceFieldType::kFtraceInt64, format.sched_switch.prev_state_type); |
| EXPECT_EQ(40u, format.sched_switch.next_comm_offset); |
| |
| // Check exact sched_waking format. |
| EXPECT_EQ(44u, format.sched_waking.event_id); |
| EXPECT_EQ(40u, format.sched_waking.size); |
| EXPECT_EQ(24u, format.sched_waking.pid_offset); |
| EXPECT_EQ(FtraceFieldType::kFtracePid32, format.sched_waking.pid_type); |
| EXPECT_EQ(36u, format.sched_waking.target_cpu_offset); |
| EXPECT_EQ(FtraceFieldType::kFtraceInt32, format.sched_waking.target_cpu_type); |
| EXPECT_EQ(28u, format.sched_waking.prio_offset); |
| EXPECT_EQ(FtraceFieldType::kFtraceInt32, format.sched_waking.prio_type); |
| EXPECT_EQ(8u, format.sched_waking.comm_offset); |
| } |
| |
| TEST(TranslationTableTest, CompactSchedFormatParsingSeedData) { |
| std::string path = |
| "src/traced/probes/ftrace/test/data/android_seed_N2F62_3.10.49/"; |
| FtraceProcfs ftrace_procfs(path); |
| auto table = ProtoTranslationTable::Create( |
| &ftrace_procfs, GetStaticEventInfo(), GetStaticCommonFieldsInfo()); |
| PERFETTO_CHECK(table); |
| const CompactSchedEventFormat& format = table->compact_sched_format(); |
| |
| // We consider the entire format invalid as there's no sched_waking event |
| // available. This is a simplifying assumption. We could instead look at each |
| // event independently (and in this case, sched_switch does match compile-time |
| // assumptions). |
| ASSERT_FALSE(format.format_valid); |
| } |
| |
| TEST(TranslationTableTest, InferFtraceType) { |
| FtraceFieldType type; |
| |
| ASSERT_TRUE(InferFtraceType("char foo[16]", 16, false, &type)); |
| EXPECT_EQ(type, kFtraceFixedCString); |
| |
| ASSERT_TRUE(InferFtraceType("char comm[TASK_COMM_LEN]", 16, false, &type)); |
| EXPECT_EQ(type, kFtraceFixedCString); |
| |
| ASSERT_TRUE(InferFtraceType("char identifier22[16]", 16, false, &type)); |
| EXPECT_EQ(type, kFtraceFixedCString); |
| |
| EXPECT_FALSE(InferFtraceType("char 2invalid[16]", 16, false, &type)); |
| |
| ASSERT_TRUE(InferFtraceType("char[] foo", 8, false, &type)); |
| EXPECT_EQ(type, kFtraceStringPtr); |
| |
| ASSERT_TRUE(InferFtraceType("char * foo", 8, false, &type)); |
| EXPECT_EQ(type, kFtraceStringPtr); |
| |
| ASSERT_TRUE(InferFtraceType("char foo[64]", 64, false, &type)); |
| EXPECT_EQ(type, kFtraceFixedCString); |
| |
| ASSERT_TRUE(InferFtraceType("u32 foo", 4, false, &type)); |
| EXPECT_EQ(type, kFtraceUint32); |
| |
| ASSERT_TRUE(InferFtraceType("i_ino foo", 4, false, &type)); |
| ASSERT_EQ(type, kFtraceInode32); |
| |
| ASSERT_TRUE(InferFtraceType("i_ino foo", 8, false, &type)); |
| ASSERT_EQ(type, kFtraceInode64); |
| |
| ASSERT_TRUE(InferFtraceType("ino_t foo", 4, false, &type)); |
| ASSERT_EQ(type, kFtraceInode32); |
| |
| ASSERT_TRUE(InferFtraceType("ino_t foo", 8, false, &type)); |
| ASSERT_EQ(type, kFtraceInode64); |
| |
| ASSERT_TRUE(InferFtraceType("dev_t foo", 4, false, &type)); |
| ASSERT_EQ(type, kFtraceDevId32); |
| |
| ASSERT_TRUE(InferFtraceType("dev_t foo", 8, false, &type)); |
| ASSERT_EQ(type, kFtraceDevId64); |
| |
| ASSERT_TRUE(InferFtraceType("pid_t foo", 4, false, &type)); |
| ASSERT_EQ(type, kFtracePid32); |
| |
| ASSERT_TRUE(InferFtraceType("int common_pid", 4, false, &type)); |
| ASSERT_EQ(type, kFtraceCommonPid32); |
| |
| ASSERT_TRUE(InferFtraceType("char foo", 1, true, &type)); |
| ASSERT_EQ(type, kFtraceInt8); |
| |
| ASSERT_TRUE(InferFtraceType("__data_loc char[] foo", 4, false, &type)); |
| ASSERT_EQ(type, kFtraceDataLoc); |
| ASSERT_FALSE(InferFtraceType("__data_loc char[] foo", 8, false, &type)); |
| |
| ASSERT_TRUE(InferFtraceType("unsigned long args[6]", 24, true, &type)); |
| ASSERT_EQ(type, kFtraceUint32); |
| ASSERT_TRUE(InferFtraceType("unsigned long args[6]", 48, true, &type)); |
| ASSERT_EQ(type, kFtraceUint64); |
| ASSERT_FALSE(InferFtraceType("unsigned long args[6]", 96, true, &type)); |
| |
| EXPECT_FALSE(InferFtraceType("foo", 64, false, &type)); |
| } |
| |
| TEST(TranslationTableTest, Getters) { |
| MockFtraceProcfs ftrace; |
| std::vector<Field> common_fields; |
| std::vector<Event> events; |
| |
| { |
| Event event{}; |
| event.name = "foo"; |
| event.group = "group_one"; |
| event.ftrace_event_id = 1; |
| events.push_back(event); |
| } |
| |
| { |
| Event event{}; |
| event.name = "bar"; |
| event.group = "group_one"; |
| event.ftrace_event_id = 2; |
| events.push_back(event); |
| } |
| |
| { |
| Event event{}; |
| event.name = "baz"; |
| event.group = "group_two"; |
| event.ftrace_event_id = 100; |
| events.push_back(event); |
| } |
| |
| ProtoTranslationTable table( |
| &ftrace, events, std::move(common_fields), |
| ProtoTranslationTable::DefaultPageHeaderSpecForTesting(), |
| InvalidCompactSchedEventFormatForTesting(), PrintkMap()); |
| |
| EXPECT_EQ(table.largest_id(), 100ul); |
| EXPECT_EQ(table.EventToFtraceId(GroupAndName("group_one", "foo")), 1ul); |
| EXPECT_EQ(table.EventToFtraceId(GroupAndName("group_two", "baz")), 100ul); |
| EXPECT_EQ(table.EventToFtraceId(GroupAndName("group_one", "no_such_event")), |
| 0ul); |
| EXPECT_EQ(table.GetEventById(1)->name, "foo"); |
| EXPECT_EQ(table.GetEventById(3), nullptr); |
| EXPECT_EQ(table.GetEventById(200), nullptr); |
| EXPECT_EQ(table.GetEventById(0), nullptr); |
| EXPECT_EQ(table.GetEvent(GroupAndName("group_one", "foo"))->ftrace_event_id, |
| 1u); |
| EXPECT_THAT(*table.GetEventsByGroup("group_one"), |
| Contains(testing::Field(&Event::name, "foo"))); |
| EXPECT_THAT(*table.GetEventsByGroup("group_one"), |
| Contains(testing::Field(&Event::name, "bar"))); |
| EXPECT_THAT(*table.GetEventsByGroup("group_two"), |
| Contains(testing::Field(&Event::name, "baz"))); |
| EXPECT_THAT(table.GetEventsByGroup("group_three"), IsNull()); |
| } |
| |
| TEST(TranslationTableTest, Generic) { |
| MockFtraceProcfs ftrace; |
| std::vector<Field> common_fields; |
| std::vector<Event> events; |
| |
| ON_CALL(ftrace, ReadPageHeaderFormat()) |
| .WillByDefault(Return( |
| R"( field: u64 timestamp; offset:0; size:8; signed:0; |
| field: local_t commit; offset:8; size:4; signed:1; |
| field: int overwrite; offset:8; size:1; signed:1; |
| field: char data; offset:16; size:4080; signed:0;)")); |
| ON_CALL(ftrace, ReadEventFormat(_, _)).WillByDefault(Return("")); |
| ON_CALL(ftrace, ReadEventFormat("group", "foo")) |
| .WillByDefault(Return(R"(name: foo |
| ID: 42 |
| format: |
| field:unsigned short common_type; offset:0; size:2; signed:0; |
| field:int common_pid; offset:4; size:4; signed:1; |
| |
| field:char field_a[16]; offset:8; size:16; signed:0; |
| field:bool field_b; offset:24; size:1; signed:0; |
| field:int field_c; offset:25; size:4; signed:1; |
| field:u32 field_d; offset:33; size:4; signed:0; |
| |
| print fmt: "some format")")); |
| |
| EXPECT_CALL(ftrace, ReadPageHeaderFormat()).Times(AnyNumber()); |
| EXPECT_CALL(ftrace, ReadEventFormat(_, _)).Times(AnyNumber()); |
| |
| auto table = ProtoTranslationTable::Create(&ftrace, std::move(events), |
| std::move(common_fields)); |
| PERFETTO_CHECK(table); |
| EXPECT_EQ(table->largest_id(), 0ul); |
| GroupAndName group_and_name("group", "foo"); |
| const Event* e = table->GetOrCreateEvent(group_and_name); |
| EXPECT_EQ(table->largest_id(), 42ul); |
| EXPECT_EQ(table->EventToFtraceId(group_and_name), 42ul); |
| |
| // Check getters |
| EXPECT_EQ(static_cast<int>(table->GetEventById(42)->proto_field_id), |
| protos::pbzero::FtraceEvent::kGenericFieldNumber); |
| EXPECT_EQ(static_cast<int>(table->GetEvent(group_and_name)->proto_field_id), |
| protos::pbzero::FtraceEvent::kGenericFieldNumber); |
| EXPECT_EQ(table->GetEventsByGroup("group")->front()->name, |
| group_and_name.name()); |
| |
| EXPECT_EQ(e->fields.size(), 4ul); |
| const std::vector<Field>& fields = e->fields; |
| // Check string field |
| const auto& str_field = fields[0]; |
| EXPECT_STREQ(str_field.ftrace_name, "field_a"); |
| EXPECT_EQ(static_cast<int>(str_field.proto_field_id), |
| protos::pbzero::GenericFtraceEvent::Field::kStrValueFieldNumber); |
| EXPECT_EQ(str_field.proto_field_type, ProtoSchemaType::kString); |
| EXPECT_EQ(str_field.ftrace_type, kFtraceFixedCString); |
| EXPECT_EQ(str_field.ftrace_size, 16); |
| EXPECT_EQ(str_field.ftrace_offset, 8); |
| |
| // Check bool field |
| const auto& bool_field = fields[1]; |
| EXPECT_STREQ(bool_field.ftrace_name, "field_b"); |
| EXPECT_EQ(static_cast<int>(bool_field.proto_field_id), |
| protos::pbzero::GenericFtraceEvent::Field::kUintValueFieldNumber); |
| EXPECT_EQ(bool_field.proto_field_type, ProtoSchemaType::kUint64); |
| EXPECT_EQ(bool_field.ftrace_type, kFtraceBool); |
| EXPECT_EQ(bool_field.ftrace_size, 1); |
| EXPECT_EQ(bool_field.ftrace_offset, 24); |
| |
| // Check int field |
| const auto& int_field = fields[2]; |
| EXPECT_STREQ(int_field.ftrace_name, "field_c"); |
| EXPECT_EQ(static_cast<int>(int_field.proto_field_id), |
| protos::pbzero::GenericFtraceEvent::Field::kIntValueFieldNumber); |
| EXPECT_EQ(int_field.proto_field_type, ProtoSchemaType::kInt64); |
| EXPECT_EQ(int_field.ftrace_type, kFtraceInt32); |
| EXPECT_EQ(int_field.ftrace_size, 4); |
| EXPECT_EQ(int_field.ftrace_offset, 25); |
| |
| // Check uint field |
| const auto& uint_field = fields[3]; |
| EXPECT_STREQ(uint_field.ftrace_name, "field_d"); |
| EXPECT_EQ(static_cast<int>(uint_field.proto_field_id), |
| protos::pbzero::GenericFtraceEvent::Field::kUintValueFieldNumber); |
| EXPECT_EQ(uint_field.proto_field_type, ProtoSchemaType::kUint64); |
| EXPECT_EQ(uint_field.ftrace_type, kFtraceUint32); |
| EXPECT_EQ(uint_field.ftrace_size, 4); |
| EXPECT_EQ(uint_field.ftrace_offset, 33); |
| } |
| |
| TEST(EventFilterTest, EnableEventsFrom) { |
| EventFilter filter; |
| filter.AddEnabledEvent(1); |
| filter.AddEnabledEvent(17); |
| |
| EventFilter or_filter; |
| or_filter.AddEnabledEvent(4); |
| or_filter.AddEnabledEvent(17); |
| |
| filter.EnableEventsFrom(or_filter); |
| EXPECT_TRUE(filter.IsEventEnabled(4)); |
| EXPECT_TRUE(filter.IsEventEnabled(17)); |
| EXPECT_TRUE(filter.IsEventEnabled(1)); |
| EXPECT_FALSE(filter.IsEventEnabled(2)); |
| |
| EventFilter empty_filter; |
| filter.EnableEventsFrom(empty_filter); |
| EXPECT_TRUE(filter.IsEventEnabled(4)); |
| EXPECT_TRUE(filter.IsEventEnabled(17)); |
| EXPECT_TRUE(filter.IsEventEnabled(1)); |
| |
| empty_filter.EnableEventsFrom(filter); |
| EXPECT_TRUE(empty_filter.IsEventEnabled(4)); |
| EXPECT_TRUE(empty_filter.IsEventEnabled(17)); |
| EXPECT_TRUE(empty_filter.IsEventEnabled(1)); |
| } |
| |
| TEST(TranslationTableTest, FuncgraphEvents) { |
| std::string path = |
| base::GetTestDataPath("src/traced/probes/ftrace/test/data/synthetic/"); |
| FtraceProcfs ftrace_procfs(path); |
| auto table = ProtoTranslationTable::Create( |
| &ftrace_procfs, GetStaticEventInfo(), GetStaticCommonFieldsInfo()); |
| PERFETTO_CHECK(table); |
| |
| { |
| auto* event = table->GetEvent(GroupAndName("ftrace", "funcgraph_entry")); |
| EXPECT_EQ(std::string(event->name), "funcgraph_entry"); |
| EXPECT_EQ(std::string(event->group), "ftrace"); |
| |
| // field:unsigned long func; offset:8; size:8; signed:0; |
| // field:int depth; offset:16; size:4; signed:1; |
| ASSERT_EQ(event->fields.size(), 2u); |
| |
| // note: fields in struct are ordered as in the proto, not the format file |
| EXPECT_THAT( |
| event->fields, |
| Contains( |
| AllOf(testing::Field(&Field::ftrace_name, StrEq("func")), |
| testing::Field(&Field::ftrace_offset, Eq(8u)), |
| testing::Field(&Field::ftrace_type, kFtraceSymAddr64), |
| testing::Field(&Field::strategy, kFtraceSymAddr64ToUint64)))); |
| } |
| { |
| auto* event = table->GetEvent(GroupAndName("ftrace", "funcgraph_exit")); |
| EXPECT_EQ(std::string(event->name), "funcgraph_exit"); |
| EXPECT_EQ(std::string(event->group), "ftrace"); |
| |
| // field:unsigned long func; offset:8; size:8; signed:0; |
| // field:int depth; offset:16; size:4; signed:1; |
| // field:unsigned int overrun; offset:20; size:4; signed:0; |
| // field:unsigned long long calltime; offset:24; size:8; signed:0; |
| // field:unsigned long long rettime; offset:32; size:8; signed:0; |
| ASSERT_EQ(event->fields.size(), 5u); |
| // note: fields in struct are ordered as in the proto, not the format file |
| EXPECT_THAT( |
| event->fields, |
| Contains( |
| AllOf(testing::Field(&Field::ftrace_name, StrEq("func")), |
| testing::Field(&Field::ftrace_offset, Eq(8u)), |
| testing::Field(&Field::ftrace_type, kFtraceSymAddr64), |
| testing::Field(&Field::strategy, kFtraceSymAddr64ToUint64)))); |
| } |
| } |
| |
| } // namespace |
| } // namespace perfetto |