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