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