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 "perfetto/ftrace_reader/ftrace_controller.h" 18 19 #include <fcntl.h> 20 #include <sys/stat.h> 21 #include <sys/types.h> 22 23 #include "perfetto/ftrace_reader/ftrace_config.h" 24 #include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h" 25 #include "perfetto/trace/trace_packet.pb.h" 26 #include "perfetto/trace/trace_packet.pbzero.h" 27 #include "src/ftrace_reader/cpu_reader.h" 28 #include "src/ftrace_reader/ftrace_config_muxer.h" 29 #include "src/ftrace_reader/ftrace_procfs.h" 30 #include "src/ftrace_reader/proto_translation_table.h" 31 #include "src/tracing/core/trace_writer_for_testing.h" 32 33 #include "gmock/gmock.h" 34 #include "gtest/gtest.h" 35 36 using testing::_; 37 using testing::AnyNumber; 38 using testing::ByMove; 39 using testing::Invoke; 40 using testing::NiceMock; 41 using testing::Return; 42 using testing::IsEmpty; 43 using testing::ElementsAre; 44 using testing::Pair; 45 46 using Table = perfetto::ProtoTranslationTable; 47 using FtraceEventBundle = perfetto::protos::pbzero::FtraceEventBundle; 48 49 namespace perfetto { 50 51 namespace { 52 53 constexpr char kFooEnablePath[] = "/root/events/group/foo/enable"; 54 constexpr char kBarEnablePath[] = "/root/events/group/bar/enable"; 55 56 class MockTaskRunner : public base::TaskRunner { 57 public: 58 MockTaskRunner() { 59 ON_CALL(*this, PostTask(_)) 60 .WillByDefault(Invoke(this, &MockTaskRunner::OnPostTask)); 61 ON_CALL(*this, PostDelayedTask(_, _)) 62 .WillByDefault(Invoke(this, &MockTaskRunner::OnPostDelayedTask)); 63 } 64 65 void OnPostTask(std::function<void()> task) { 66 std::unique_lock<std::mutex> lock(lock_); 67 EXPECT_FALSE(task_); 68 task_ = std::move(task); 69 } 70 71 void OnPostDelayedTask(std::function<void()> task, int /*delay*/) { 72 std::unique_lock<std::mutex> lock(lock_); 73 EXPECT_FALSE(task_); 74 task_ = std::move(task); 75 } 76 77 void RunLastTask() { TakeTask()(); } 78 79 std::function<void()> TakeTask() { 80 std::unique_lock<std::mutex> lock(lock_); 81 return std::move(task_); 82 } 83 84 MOCK_METHOD1(PostTask, void(std::function<void()>)); 85 MOCK_METHOD2(PostDelayedTask, void(std::function<void()>, uint32_t delay_ms)); 86 MOCK_METHOD2(AddFileDescriptorWatch, void(int fd, std::function<void()>)); 87 MOCK_METHOD1(RemoveFileDescriptorWatch, void(int fd)); 88 89 private: 90 std::mutex lock_; 91 std::function<void()> task_; 92 }; 93 94 class MockDelegate : public perfetto::FtraceSink::Delegate { 95 public: 96 MOCK_METHOD1(GetBundleForCpu, 97 protozero::MessageHandle<FtraceEventBundle>(size_t)); 98 MOCK_METHOD3(OnBundleComplete_, 99 void(size_t, 100 protozero::MessageHandle<FtraceEventBundle>&, 101 const FtraceMetadata& metadata)); 102 103 void OnBundleComplete(size_t cpu, 104 protozero::MessageHandle<FtraceEventBundle> bundle, 105 const FtraceMetadata& metadata) override { 106 OnBundleComplete_(cpu, bundle, metadata); 107 } 108 }; 109 110 std::unique_ptr<Table> FakeTable() { 111 std::vector<Field> common_fields; 112 std::vector<Event> events; 113 114 { 115 Event event; 116 event.name = "foo"; 117 event.group = "group"; 118 event.ftrace_event_id = 1; 119 events.push_back(event); 120 } 121 122 { 123 Event event; 124 event.name = "bar"; 125 event.group = "group"; 126 event.ftrace_event_id = 10; 127 events.push_back(event); 128 } 129 130 return std::unique_ptr<Table>(new Table(events, std::move(common_fields))); 131 } 132 133 std::unique_ptr<FtraceConfigMuxer> FakeModel( 134 FtraceProcfs* ftrace, 135 const ProtoTranslationTable* table) { 136 return std::unique_ptr<FtraceConfigMuxer>( 137 new FtraceConfigMuxer(ftrace, table)); 138 } 139 140 class MockFtraceProcfs : public FtraceProcfs { 141 public: 142 explicit MockFtraceProcfs(size_t cpu_count = 1) : FtraceProcfs("/root/") { 143 ON_CALL(*this, NumberOfCpus()).WillByDefault(Return(cpu_count)); 144 EXPECT_CALL(*this, NumberOfCpus()).Times(AnyNumber()); 145 146 ON_CALL(*this, ReadFileIntoString("/root/trace_clock")) 147 .WillByDefault(Return("local global [boot]")); 148 EXPECT_CALL(*this, ReadFileIntoString("/root/trace_clock")) 149 .Times(AnyNumber()); 150 151 ON_CALL(*this, WriteToFile(_, _)).WillByDefault(Return(true)); 152 ON_CALL(*this, ClearFile(_)).WillByDefault(Return(true)); 153 154 ON_CALL(*this, WriteToFile("/root/tracing_on", _)) 155 .WillByDefault(Invoke(this, &MockFtraceProcfs::WriteTracingOn)); 156 ON_CALL(*this, ReadOneCharFromFile("/root/tracing_on")) 157 .WillByDefault(Invoke(this, &MockFtraceProcfs::ReadTracingOn)); 158 EXPECT_CALL(*this, ReadOneCharFromFile("/root/tracing_on")) 159 .Times(AnyNumber()); 160 } 161 162 bool WriteTracingOn(const std::string& /*path*/, const std::string& value) { 163 PERFETTO_CHECK(value == "1" || value == "0"); 164 tracing_on_ = value == "1"; 165 return true; 166 } 167 168 char ReadTracingOn(const std::string& /*path*/) { 169 return tracing_on_ ? '1' : '0'; 170 } 171 172 base::ScopedFile OpenPipeForCpu(size_t /*cpu*/) override { 173 return base::ScopedFile(open("/dev/null", O_RDONLY)); 174 } 175 176 MOCK_METHOD2(WriteToFile, 177 bool(const std::string& path, const std::string& str)); 178 MOCK_CONST_METHOD0(NumberOfCpus, size_t()); 179 MOCK_METHOD1(ReadOneCharFromFile, char(const std::string& path)); 180 MOCK_METHOD1(ClearFile, bool(const std::string& path)); 181 MOCK_CONST_METHOD1(ReadFileIntoString, std::string(const std::string& path)); 182 183 bool is_tracing_on() { return tracing_on_; } 184 185 private: 186 bool tracing_on_ = false; 187 }; 188 189 } // namespace 190 191 class TestFtraceController : public FtraceController { 192 public: 193 TestFtraceController(std::unique_ptr<MockFtraceProcfs> ftrace_procfs, 194 std::unique_ptr<Table> table, 195 std::unique_ptr<FtraceConfigMuxer> model, 196 std::unique_ptr<MockTaskRunner> runner, 197 MockFtraceProcfs* raw_procfs) 198 : FtraceController(std::move(ftrace_procfs), 199 std::move(table), 200 std::move(model), 201 runner.get()), 202 runner_(std::move(runner)), 203 procfs_(raw_procfs) {} 204 205 MOCK_METHOD1(OnRawFtraceDataAvailable, void(size_t cpu)); 206 207 MockTaskRunner* runner() { return runner_.get(); } 208 MockFtraceProcfs* procfs() { return procfs_; } 209 210 uint64_t NowMs() const override { return now_ms; } 211 212 uint32_t drain_period_ms() { return GetDrainPeriodMs(); } 213 214 std::function<void()> GetDataAvailableCallback(size_t cpu) { 215 base::WeakPtr<FtraceController> weak_this = weak_factory_.GetWeakPtr(); 216 size_t generation = generation_; 217 return [this, weak_this, generation, cpu] { 218 OnDataAvailable(weak_this, generation, cpu, GetDrainPeriodMs()); 219 }; 220 } 221 222 void WaitForData(size_t cpu) { 223 while (true) { 224 { 225 std::unique_lock<std::mutex> lock(lock_); 226 if (cpus_to_drain_[cpu]) 227 return; 228 } 229 usleep(5000); 230 } 231 } 232 233 uint64_t now_ms = 0; 234 235 private: 236 TestFtraceController(const TestFtraceController&) = delete; 237 TestFtraceController& operator=(const TestFtraceController&) = delete; 238 239 std::unique_ptr<MockTaskRunner> runner_; 240 MockFtraceProcfs* procfs_; 241 }; 242 243 namespace { 244 245 std::unique_ptr<TestFtraceController> CreateTestController( 246 bool runner_is_nice_mock, 247 bool procfs_is_nice_mock, 248 size_t cpu_count = 1) { 249 std::unique_ptr<MockTaskRunner> runner; 250 if (runner_is_nice_mock) { 251 runner = std::unique_ptr<MockTaskRunner>(new NiceMock<MockTaskRunner>()); 252 } else { 253 runner = std::unique_ptr<MockTaskRunner>(new MockTaskRunner()); 254 } 255 256 auto table = FakeTable(); 257 258 std::unique_ptr<MockFtraceProcfs> ftrace_procfs; 259 if (procfs_is_nice_mock) { 260 ftrace_procfs = std::unique_ptr<MockFtraceProcfs>( 261 new NiceMock<MockFtraceProcfs>(cpu_count)); 262 } else { 263 ftrace_procfs = 264 std::unique_ptr<MockFtraceProcfs>(new MockFtraceProcfs(cpu_count)); 265 } 266 267 auto model = FakeModel(ftrace_procfs.get(), table.get()); 268 269 MockFtraceProcfs* raw_procfs = ftrace_procfs.get(); 270 return std::unique_ptr<TestFtraceController>(new TestFtraceController( 271 std::move(ftrace_procfs), std::move(table), std::move(model), 272 std::move(runner), raw_procfs)); 273 } 274 275 } // namespace 276 277 TEST(FtraceControllerTest, NonExistentEventsDontCrash) { 278 auto controller = 279 CreateTestController(true /* nice runner */, true /* nice procfs */); 280 281 MockDelegate delegate; 282 FtraceConfig config = CreateFtraceConfig({"not_an_event"}); 283 284 std::unique_ptr<FtraceSink> sink = controller->CreateSink(config, &delegate); 285 } 286 287 TEST(FtraceControllerTest, RejectsBadEventNames) { 288 auto controller = 289 CreateTestController(true /* nice runner */, true /* nice procfs */); 290 291 MockDelegate delegate; 292 FtraceConfig config = CreateFtraceConfig({"../try/to/escape"}); 293 EXPECT_FALSE(controller->CreateSink(config, &delegate)); 294 EXPECT_FALSE(controller->procfs()->is_tracing_on()); 295 } 296 297 TEST(FtraceControllerTest, OneSink) { 298 auto controller = 299 CreateTestController(true /* nice runner */, false /* nice procfs */); 300 301 MockDelegate delegate; 302 FtraceConfig config = CreateFtraceConfig({"foo"}); 303 304 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1")); 305 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1")); 306 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _)); 307 std::unique_ptr<FtraceSink> sink = controller->CreateSink(config, &delegate); 308 309 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", "0")); 310 EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace")) 311 .WillOnce(Return(true)); 312 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0")); 313 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0")); 314 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0")); 315 EXPECT_TRUE(controller->procfs()->is_tracing_on()); 316 317 sink.reset(); 318 EXPECT_FALSE(controller->procfs()->is_tracing_on()); 319 } 320 321 TEST(FtraceControllerTest, MultipleSinks) { 322 auto controller = 323 CreateTestController(false /* nice runner */, false /* nice procfs */); 324 325 MockDelegate delegate; 326 327 FtraceConfig configA = CreateFtraceConfig({"foo"}); 328 FtraceConfig configB = CreateFtraceConfig({"foo", "bar"}); 329 330 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1")); 331 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _)); 332 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1")); 333 std::unique_ptr<FtraceSink> sinkA = 334 controller->CreateSink(configA, &delegate); 335 336 EXPECT_CALL(*controller->procfs(), WriteToFile(kBarEnablePath, "1")); 337 std::unique_ptr<FtraceSink> sinkB = 338 controller->CreateSink(configB, &delegate); 339 340 sinkA.reset(); 341 342 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0")); 343 EXPECT_CALL(*controller->procfs(), WriteToFile(kBarEnablePath, "0")); 344 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", "0")); 345 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0")); 346 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0")); 347 EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace")); 348 sinkB.reset(); 349 } 350 351 TEST(FtraceControllerTest, ControllerMayDieFirst) { 352 auto controller = 353 CreateTestController(false /* nice runner */, false /* nice procfs */); 354 355 MockDelegate delegate; 356 FtraceConfig config = CreateFtraceConfig({"foo"}); 357 358 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _)); 359 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1")); 360 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1")); 361 std::unique_ptr<FtraceSink> sink = controller->CreateSink(config, &delegate); 362 363 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0")); 364 EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace")) 365 .WillOnce(Return(true)); 366 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0")); 367 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", "0")); 368 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0")); 369 controller.reset(); 370 371 sink.reset(); 372 } 373 374 TEST(FtraceControllerTest, TaskScheduling) { 375 auto controller = CreateTestController( 376 false /* nice runner */, false /* nice procfs */, 2 /* num cpus */); 377 378 // For this test we don't care about calls to WriteToFile/ClearFile. 379 EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber()); 380 EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber()); 381 382 MockDelegate delegate; 383 FtraceConfig config = CreateFtraceConfig({"foo"}); 384 385 std::unique_ptr<FtraceSink> sink = controller->CreateSink(config, &delegate); 386 387 // Only one call to drain should be scheduled for the next drain period. 388 EXPECT_CALL(*controller->runner(), PostDelayedTask(_, 100)); 389 390 // However both CPUs should be drained. 391 EXPECT_CALL(*controller, OnRawFtraceDataAvailable(_)).Times(2); 392 393 // Finally, another task should be posted to unblock the workers. 394 EXPECT_CALL(*controller->runner(), PostTask(_)); 395 396 // Simulate two worker threads reporting available data. 397 auto on_data_available0 = controller->GetDataAvailableCallback(0u); 398 std::thread worker0([on_data_available0] { on_data_available0(); }); 399 400 auto on_data_available1 = controller->GetDataAvailableCallback(1u); 401 std::thread worker1([on_data_available1] { on_data_available1(); }); 402 403 // Poll until both worker threads have reported available data. 404 controller->WaitForData(0u); 405 controller->WaitForData(1u); 406 407 // Run the task to drain all CPUs. 408 controller->runner()->RunLastTask(); 409 410 // Run the task to unblock all workers. 411 controller->runner()->RunLastTask(); 412 413 worker0.join(); 414 worker1.join(); 415 416 sink.reset(); 417 } 418 419 // TODO(b/73452932): Fix and reenable this test. 420 TEST(FtraceControllerTest, DISABLED_DrainPeriodRespected) { 421 auto controller = 422 CreateTestController(false /* nice runner */, false /* nice procfs */); 423 424 // For this test we don't care about calls to WriteToFile/ClearFile. 425 EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber()); 426 EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber()); 427 428 MockDelegate delegate; 429 FtraceConfig config = CreateFtraceConfig({"foo"}); 430 431 // Test several cycles of a worker producing data and make sure the drain 432 // delay is consistent with the drain period. 433 std::unique_ptr<FtraceSink> sink = controller->CreateSink(config, &delegate); 434 435 const int kCycles = 50; 436 EXPECT_CALL(*controller->runner(), 437 PostDelayedTask(_, controller->drain_period_ms())) 438 .Times(kCycles); 439 EXPECT_CALL(*controller, OnRawFtraceDataAvailable(_)).Times(kCycles); 440 EXPECT_CALL(*controller->runner(), PostTask(_)).Times(kCycles); 441 442 // Simulate a worker thread continually reporting pages of available data. 443 auto on_data_available = controller->GetDataAvailableCallback(0u); 444 std::thread worker([on_data_available] { 445 for (int i = 0; i < kCycles; i++) 446 on_data_available(); 447 }); 448 449 for (int i = 0; i < kCycles; i++) { 450 controller->WaitForData(0u); 451 // Run two tasks: one to drain each CPU and another to unblock the worker. 452 controller->runner()->RunLastTask(); 453 controller->runner()->RunLastTask(); 454 controller->now_ms += controller->drain_period_ms(); 455 } 456 457 worker.join(); 458 sink.reset(); 459 } 460 461 TEST(FtraceControllerTest, BackToBackEnableDisable) { 462 auto controller = 463 CreateTestController(false /* nice runner */, false /* nice procfs */); 464 465 // For this test we don't care about calls to WriteToFile/ClearFile. 466 EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber()); 467 EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber()); 468 EXPECT_CALL(*controller->procfs(), ReadOneCharFromFile("/root/tracing_on")) 469 .Times(AnyNumber()); 470 471 MockDelegate delegate; 472 FtraceConfig config = CreateFtraceConfig({"foo"}); 473 474 EXPECT_CALL(*controller->runner(), PostDelayedTask(_, 100)).Times(2); 475 std::unique_ptr<FtraceSink> sink_a = 476 controller->CreateSink(config, &delegate); 477 478 auto on_data_available = controller->GetDataAvailableCallback(0u); 479 std::thread worker([on_data_available] { on_data_available(); }); 480 controller->WaitForData(0u); 481 482 // Disable the first sink and run the delayed task that it generated. It 483 // should be a no-op. 484 sink_a.reset(); 485 controller->runner()->RunLastTask(); 486 worker.join(); 487 488 // Register another sink and wait for it to generate data. 489 std::unique_ptr<FtraceSink> sink_b = 490 controller->CreateSink(config, &delegate); 491 std::thread worker2([on_data_available] { on_data_available(); }); 492 controller->WaitForData(0u); 493 494 // This drain should also be a no-op after the sink is unregistered. 495 sink_b.reset(); 496 controller->runner()->RunLastTask(); 497 worker2.join(); 498 } 499 500 TEST(FtraceControllerTest, BufferSize) { 501 auto controller = 502 CreateTestController(true /* nice runner */, false /* nice procfs */); 503 504 // For this test we don't care about most calls to WriteToFile/ClearFile. 505 EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber()); 506 EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber()); 507 MockDelegate delegate; 508 509 { 510 // No buffer size -> good default. 511 // 8192kb = 8mb 512 EXPECT_CALL(*controller->procfs(), 513 WriteToFile("/root/buffer_size_kb", "512")); 514 FtraceConfig config = CreateFtraceConfig({"foo"}); 515 auto sink = controller->CreateSink(config, &delegate); 516 } 517 518 { 519 // Way too big buffer size -> max size. 520 EXPECT_CALL(*controller->procfs(), 521 WriteToFile("/root/buffer_size_kb", "65536")); 522 FtraceConfig config = CreateFtraceConfig({"foo"}); 523 config.set_buffer_size_kb(10 * 1024 * 1024); 524 auto sink = controller->CreateSink(config, &delegate); 525 } 526 527 { 528 // The limit is 64mb, 65mb is too much. 529 EXPECT_CALL(*controller->procfs(), 530 WriteToFile("/root/buffer_size_kb", "65536")); 531 FtraceConfig config = CreateFtraceConfig({"foo"}); 532 ON_CALL(*controller->procfs(), NumberOfCpus()).WillByDefault(Return(2)); 533 config.set_buffer_size_kb(65 * 1024); 534 auto sink = controller->CreateSink(config, &delegate); 535 } 536 537 { 538 // Your size ends up with less than 1 page per cpu -> 1 page. 539 EXPECT_CALL(*controller->procfs(), 540 WriteToFile("/root/buffer_size_kb", "4")); 541 FtraceConfig config = CreateFtraceConfig({"foo"}); 542 config.set_buffer_size_kb(1); 543 auto sink = controller->CreateSink(config, &delegate); 544 } 545 546 { 547 // You picked a good size -> your size rounded to nearest page. 548 EXPECT_CALL(*controller->procfs(), 549 WriteToFile("/root/buffer_size_kb", "40")); 550 FtraceConfig config = CreateFtraceConfig({"foo"}); 551 config.set_buffer_size_kb(42); 552 auto sink = controller->CreateSink(config, &delegate); 553 } 554 555 { 556 // You picked a good size -> your size rounded to nearest page. 557 EXPECT_CALL(*controller->procfs(), 558 WriteToFile("/root/buffer_size_kb", "40")); 559 FtraceConfig config = CreateFtraceConfig({"foo"}); 560 ON_CALL(*controller->procfs(), NumberOfCpus()).WillByDefault(Return(2)); 561 config.set_buffer_size_kb(42); 562 auto sink = controller->CreateSink(config, &delegate); 563 } 564 } 565 566 TEST(FtraceControllerTest, PeriodicDrainConfig) { 567 auto controller = 568 CreateTestController(true /* nice runner */, false /* nice procfs */); 569 570 // For this test we don't care about calls to WriteToFile/ClearFile. 571 EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber()); 572 EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber()); 573 MockDelegate delegate; 574 575 { 576 // No period -> good default. 577 FtraceConfig config = CreateFtraceConfig({"foo"}); 578 auto sink = controller->CreateSink(config, &delegate); 579 EXPECT_EQ(100u, controller->drain_period_ms()); 580 } 581 582 { 583 // Pick a tiny value -> good default. 584 FtraceConfig config = CreateFtraceConfig({"foo"}); 585 config.set_drain_period_ms(0); 586 auto sink = controller->CreateSink(config, &delegate); 587 EXPECT_EQ(100u, controller->drain_period_ms()); 588 } 589 590 { 591 // Pick a huge value -> good default. 592 FtraceConfig config = CreateFtraceConfig({"foo"}); 593 config.set_drain_period_ms(1000 * 60 * 60); 594 auto sink = controller->CreateSink(config, &delegate); 595 EXPECT_EQ(100u, controller->drain_period_ms()); 596 } 597 598 { 599 // Pick a resonable value -> get that value. 600 FtraceConfig config = CreateFtraceConfig({"foo"}); 601 config.set_drain_period_ms(200); 602 auto sink = controller->CreateSink(config, &delegate); 603 EXPECT_EQ(200u, controller->drain_period_ms()); 604 } 605 } 606 607 TEST(FtraceMetadataTest, Clear) { 608 FtraceMetadata metadata; 609 metadata.inode_and_device.push_back(std::make_pair(1, 1)); 610 metadata.pids.push_back(2); 611 metadata.overwrite_count = 3; 612 metadata.last_seen_device_id = 100; 613 metadata.Clear(); 614 EXPECT_THAT(metadata.inode_and_device, IsEmpty()); 615 EXPECT_THAT(metadata.pids, IsEmpty()); 616 EXPECT_EQ(0u, metadata.overwrite_count); 617 EXPECT_EQ(BlockDeviceID(0), metadata.last_seen_device_id); 618 } 619 620 TEST(FtraceMetadataTest, AddDevice) { 621 FtraceMetadata metadata; 622 metadata.AddDevice(1); 623 EXPECT_EQ(BlockDeviceID(1), metadata.last_seen_device_id); 624 metadata.AddDevice(3); 625 EXPECT_EQ(BlockDeviceID(3), metadata.last_seen_device_id); 626 } 627 628 TEST(FtraceMetadataTest, AddInode) { 629 FtraceMetadata metadata; 630 metadata.AddCommonPid(getpid() + 1); 631 metadata.AddDevice(3); 632 metadata.AddInode(2); 633 metadata.AddInode(1); 634 metadata.AddCommonPid(getpid() + 1); 635 metadata.AddDevice(4); 636 metadata.AddInode(3); 637 638 // Check activity from ourselves is excluded. 639 metadata.AddCommonPid(getpid()); 640 metadata.AddDevice(5); 641 metadata.AddInode(5); 642 643 EXPECT_THAT(metadata.inode_and_device, 644 ElementsAre(Pair(2, 3), Pair(1, 3), Pair(3, 4))); 645 } 646 647 TEST(FtraceMetadataTest, AddPid) { 648 FtraceMetadata metadata; 649 metadata.AddPid(1); 650 metadata.AddPid(2); 651 metadata.AddPid(2); 652 metadata.AddPid(3); 653 EXPECT_THAT(metadata.pids, ElementsAre(1, 2, 3)); 654 } 655 656 TEST(FtraceStatsTest, Write) { 657 FtraceStats stats{}; 658 FtraceCpuStats cpu_stats{}; 659 cpu_stats.cpu = 0; 660 cpu_stats.entries = 1; 661 cpu_stats.overrun = 2; 662 stats.cpu_stats.push_back(cpu_stats); 663 664 std::unique_ptr<TraceWriterForTesting> writer = 665 std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting()); 666 { 667 auto packet = writer->NewTracePacket(); 668 auto* out = packet->set_ftrace_stats(); 669 stats.Write(out); 670 } 671 672 std::unique_ptr<protos::TracePacket> result_packet = writer->ParseProto(); 673 auto result = result_packet->ftrace_stats().cpu_stats(0); 674 EXPECT_EQ(result.cpu(), 0); 675 EXPECT_EQ(result.entries(), 1); 676 EXPECT_EQ(result.overrun(), 2); 677 } 678 679 } // namespace perfetto 680