Home | History | Annotate | Download | only in ftrace_reader
      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