xref: /aosp_15_r20/external/perfetto/src/traced/probes/ftrace/ftrace_controller_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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/ftrace_controller.h"
18 
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 
23 #include "perfetto/ext/base/file_utils.h"
24 #include "src/traced/probes/ftrace/compact_sched.h"
25 #include "src/traced/probes/ftrace/cpu_reader.h"
26 #include "src/traced/probes/ftrace/ftrace_config_muxer.h"
27 #include "src/traced/probes/ftrace/ftrace_config_utils.h"
28 #include "src/traced/probes/ftrace/ftrace_data_source.h"
29 #include "src/traced/probes/ftrace/ftrace_procfs.h"
30 #include "src/traced/probes/ftrace/proto_translation_table.h"
31 #include "src/tracing/core/trace_writer_for_testing.h"
32 #include "test/gtest_and_gmock.h"
33 
34 #include "protos/perfetto/trace/ftrace/ftrace_stats.gen.h"
35 #include "protos/perfetto/trace/ftrace/ftrace_stats.pbzero.h"
36 #include "protos/perfetto/trace/trace_packet.gen.h"
37 #include "protos/perfetto/trace/trace_packet.pbzero.h"
38 
39 using testing::_;
40 using testing::AnyNumber;
41 using testing::ByMove;
42 using testing::ElementsAre;
43 using testing::Invoke;
44 using testing::IsEmpty;
45 using testing::MatchesRegex;
46 using testing::Mock;
47 using testing::NiceMock;
48 using testing::Pair;
49 using testing::Return;
50 using testing::UnorderedElementsAre;
51 
52 using Table = perfetto::ProtoTranslationTable;
53 
54 namespace perfetto {
55 
56 namespace {
57 
58 constexpr char kFooEnablePath[] = "/root/events/group/foo/enable";
59 constexpr char kBarEnablePath[] = "/root/events/group/bar/enable";
60 
PageSizeKb()61 std::string PageSizeKb() {
62   return std::to_string(base::GetSysPageSize() / 1024);
63 }
64 
65 class MockTaskRunner : public base::TaskRunner {
66  public:
67   MOCK_METHOD(void, PostTask, (std::function<void()>), (override));
68   MOCK_METHOD(void,
69               PostDelayedTask,
70               (std::function<void()>, uint32_t delay_ms),
71               (override));
72   MOCK_METHOD(void,
73               AddFileDescriptorWatch,
74               (int fd, std::function<void()>),
75               (override));
76   MOCK_METHOD(void, RemoveFileDescriptorWatch, (int fd), (override));
77   MOCK_METHOD(bool, RunsTasksOnCurrentThread, (), (const, override));
78 };
79 
FakeTable(FtraceProcfs * ftrace)80 std::unique_ptr<Table> FakeTable(FtraceProcfs* ftrace) {
81   std::vector<Field> common_fields;
82   std::vector<Event> events;
83   {
84     events.push_back(Event{});
85     auto& event = events.back();
86     event.name = "foo";
87     event.group = "group";
88     event.ftrace_event_id = 1;
89   }
90   {
91     events.push_back(Event{});
92     auto& event = events.back();
93     event.name = "bar";
94     event.group = "group";
95     event.ftrace_event_id = 10;
96   }
97 
98   return std::unique_ptr<Table>(
99       new Table(ftrace, events, std::move(common_fields),
100                 ProtoTranslationTable::DefaultPageHeaderSpecForTesting(),
101                 InvalidCompactSchedEventFormatForTesting(), PrintkMap()));
102 }
103 
FakeMuxer(FtraceProcfs * ftrace,AtraceWrapper * atrace_wrapper,ProtoTranslationTable * table)104 std::unique_ptr<FtraceConfigMuxer> FakeMuxer(FtraceProcfs* ftrace,
105                                              AtraceWrapper* atrace_wrapper,
106                                              ProtoTranslationTable* table) {
107   return std::unique_ptr<FtraceConfigMuxer>(new FtraceConfigMuxer(
108       ftrace, atrace_wrapper, table, SyscallTable(Architecture::kUnknown), {}));
109 }
110 
111 class MockFtraceProcfs : public FtraceProcfs {
112  public:
MockFtraceProcfs(const std::string & root,size_t cpu_count=1)113   explicit MockFtraceProcfs(const std::string& root, size_t cpu_count = 1)
114       : FtraceProcfs(root) {
115     ON_CALL(*this, NumberOfCpus()).WillByDefault(Return(cpu_count));
116     EXPECT_CALL(*this, NumberOfCpus()).Times(AnyNumber());
117 
118     ON_CALL(*this, ReadFileIntoString(root + "trace_clock"))
119         .WillByDefault(Return("local global [boot]"));
120     EXPECT_CALL(*this, ReadFileIntoString(root + "trace_clock"))
121         .Times(AnyNumber());
122 
123     ON_CALL(*this, ReadFileIntoString(root + "per_cpu/cpu0/stats"))
124         .WillByDefault(Return(""));
125     EXPECT_CALL(*this, ReadFileIntoString(root + "per_cpu/cpu0/stats"))
126         .Times(AnyNumber());
127 
128     ON_CALL(*this, ReadFileIntoString(root + "events//not_an_event/format"))
129         .WillByDefault(Return(""));
130     EXPECT_CALL(*this, ReadFileIntoString(root + "events//not_an_event/format"))
131         .Times(AnyNumber());
132 
133     ON_CALL(*this, ReadFileIntoString(root + "events/group/bar/format"))
134         .WillByDefault(Return(""));
135     EXPECT_CALL(*this, ReadFileIntoString(root + "events/group/bar/format"))
136         .Times(AnyNumber());
137 
138     ON_CALL(*this, WriteToFile(_, _)).WillByDefault(Return(true));
139     ON_CALL(*this, ClearFile(_)).WillByDefault(Return(true));
140 
141     ON_CALL(*this, WriteToFile(root + "tracing_on", _))
142         .WillByDefault(Invoke(this, &MockFtraceProcfs::WriteTracingOn));
143     ON_CALL(*this, ReadOneCharFromFile(root + "tracing_on"))
144         .WillByDefault(Invoke(this, &MockFtraceProcfs::ReadTracingOn));
145     EXPECT_CALL(*this, ReadOneCharFromFile(root + "tracing_on"))
146         .Times(AnyNumber());
147 
148     ON_CALL(*this, WriteToFile(root + "current_tracer", _))
149         .WillByDefault(Invoke(this, &MockFtraceProcfs::WriteCurrentTracer));
150     ON_CALL(*this, ReadFileIntoString(root + "current_tracer"))
151         .WillByDefault(Invoke(this, &MockFtraceProcfs::ReadCurrentTracer));
152     EXPECT_CALL(*this, ReadFileIntoString(root + "current_tracer"))
153         .Times(AnyNumber());
154 
155     ON_CALL(*this, ReadFileIntoString(root + "buffer_percent"))
156         .WillByDefault(Return("50\n"));
157     EXPECT_CALL(*this, ReadFileIntoString(root + "buffer_percent"))
158         .Times(AnyNumber());
159   }
160 
WriteTracingOn(const std::string &,const std::string & value)161   bool WriteTracingOn(const std::string& /*path*/, const std::string& value) {
162     PERFETTO_CHECK(value == "1" || value == "0");
163     tracing_on_ = value == "1";
164     return true;
165   }
166 
ReadTracingOn(const std::string &)167   char ReadTracingOn(const std::string& /*path*/) {
168     return tracing_on_ ? '1' : '0';
169   }
170 
WriteCurrentTracer(const std::string &,const std::string & value)171   bool WriteCurrentTracer(const std::string& /*path*/,
172                           const std::string& value) {
173     current_tracer_ = value;
174     return true;
175   }
176 
ReadCurrentTracer(const std::string &)177   std::string ReadCurrentTracer(const std::string& /*path*/) {
178     return current_tracer_;
179   }
180 
OpenPipeForCpu(size_t)181   base::ScopedFile OpenPipeForCpu(size_t /*cpu*/) override {
182     return base::ScopedFile(base::OpenFile("/dev/null", O_RDONLY));
183   }
184 
185   MOCK_METHOD(bool,
186               WriteToFile,
187               (const std::string& path, const std::string& str),
188               (override));
189   MOCK_METHOD(size_t, NumberOfCpus, (), (const, override));
190   MOCK_METHOD(char, ReadOneCharFromFile, (const std::string& path), (override));
191   MOCK_METHOD(bool, ClearFile, (const std::string& path), (override));
192   MOCK_METHOD(bool, IsFileWriteable, (const std::string& path), (override));
193   MOCK_METHOD(std::string,
194               ReadFileIntoString,
195               (const std::string& path),
196               (const, override));
197 
is_tracing_on()198   bool is_tracing_on() { return tracing_on_; }
199 
200  private:
201   bool tracing_on_ = true;
202   std::string current_tracer_ = "nop";
203 };
204 
205 class MockAtraceWrapper : public AtraceWrapper {
206  public:
207   MOCK_METHOD(bool, RunAtrace, (const std::vector<std::string>&, std::string*));
208   MOCK_METHOD(bool, SupportsUserspaceOnly, ());
209   MOCK_METHOD(bool, SupportsPreferSdk, ());
210 };
211 
212 }  // namespace
213 
214 class TestFtraceController : public FtraceController,
215                              public FtraceController::Observer {
216  public:
TestFtraceController(std::unique_ptr<MockFtraceProcfs> ftrace_procfs,std::unique_ptr<Table> table,std::unique_ptr<AtraceWrapper> atrace_wrapper,std::unique_ptr<FtraceConfigMuxer> muxer,std::unique_ptr<MockTaskRunner> runner,MockFtraceProcfs * raw_procfs)217   TestFtraceController(std::unique_ptr<MockFtraceProcfs> ftrace_procfs,
218                        std::unique_ptr<Table> table,
219                        std::unique_ptr<AtraceWrapper> atrace_wrapper,
220                        std::unique_ptr<FtraceConfigMuxer> muxer,
221                        std::unique_ptr<MockTaskRunner> runner,
222                        MockFtraceProcfs* raw_procfs)
223       : FtraceController(std::move(ftrace_procfs),
224                          std::move(table),
225                          std::move(atrace_wrapper),
226                          std::move(muxer),
227                          runner.get(),
228                          /*observer=*/this),
229         runner_(std::move(runner)),
230         primary_procfs_(raw_procfs) {}
231 
runner()232   MockTaskRunner* runner() { return runner_.get(); }
procfs()233   MockFtraceProcfs* procfs() { return primary_procfs_; }
tick_period_ms()234   uint32_t tick_period_ms() { return GetTickPeriodMs(); }
235 
AddFakeDataSource(const FtraceConfig & cfg)236   std::unique_ptr<FtraceDataSource> AddFakeDataSource(const FtraceConfig& cfg) {
237     std::unique_ptr<FtraceDataSource> data_source(new FtraceDataSource(
238         GetWeakPtr(), 0 /* session id */, cfg, nullptr /* trace_writer */));
239     if (!AddDataSource(data_source.get()))
240       return nullptr;
241     return data_source;
242   }
243 
NowMs() const244   uint64_t NowMs() const override { return 0; }
OnFtraceDataWrittenIntoDataSourceBuffers()245   void OnFtraceDataWrittenIntoDataSourceBuffers() override {}
246 
InstanceExists(const std::string & instance_name)247   bool InstanceExists(const std::string& instance_name) {
248     auto* instance = GetInstance(instance_name);
249     return instance != nullptr;
250   }
251 
PrepareMockProcfsForInstance(const std::string & name,std::unique_ptr<MockFtraceProcfs> fs)252   void PrepareMockProcfsForInstance(const std::string& name,
253                                     std::unique_ptr<MockFtraceProcfs> fs) {
254     pending_instance_procfs_[name] = std::move(fs);
255   }
256 
GetInstanceMockProcfs(const std::string & instance_name)257   MockFtraceProcfs* GetInstanceMockProcfs(const std::string& instance_name) {
258     auto* instance = GetInstance(instance_name);
259     PERFETTO_CHECK(instance);
260     return reinterpret_cast<MockFtraceProcfs*>(instance->ftrace_procfs.get());
261   }
262 
CreateSecondaryInstance(const std::string & instance_name)263   std::unique_ptr<FtraceInstanceState> CreateSecondaryInstance(
264       const std::string& instance_name) override {
265     auto ftrace_procfs = std::move(pending_instance_procfs_[instance_name]);
266     PERFETTO_CHECK(ftrace_procfs);
267 
268     auto table = FakeTable(ftrace_procfs.get());
269     auto muxer = FakeMuxer(ftrace_procfs.get(), atrace_wrapper(), table.get());
270     return std::unique_ptr<FtraceController::FtraceInstanceState>(
271         new FtraceController::FtraceInstanceState(
272             std::move(ftrace_procfs), std::move(table), std::move(muxer)));
273   }
274 
275  private:
276   TestFtraceController(const TestFtraceController&) = delete;
277   TestFtraceController& operator=(const TestFtraceController&) = delete;
278 
279   std::unique_ptr<MockTaskRunner> runner_;
280   MockFtraceProcfs* primary_procfs_;
281   std::map<std::string, std::unique_ptr<MockFtraceProcfs>>
282       pending_instance_procfs_;
283 };
284 
285 namespace {
286 
CreateTestController(bool procfs_is_nice_mock,size_t cpu_count=1)287 std::unique_ptr<TestFtraceController> CreateTestController(
288     bool procfs_is_nice_mock,
289     size_t cpu_count = 1) {
290   std::unique_ptr<MockTaskRunner> runner =
291       std::unique_ptr<MockTaskRunner>(new NiceMock<MockTaskRunner>());
292 
293   std::unique_ptr<MockFtraceProcfs> ftrace_procfs;
294   if (procfs_is_nice_mock) {
295     ftrace_procfs = std::unique_ptr<MockFtraceProcfs>(
296         new NiceMock<MockFtraceProcfs>("/root/", cpu_count));
297   } else {
298     ftrace_procfs = std::unique_ptr<MockFtraceProcfs>(
299         new MockFtraceProcfs("/root/", cpu_count));
300   }
301 
302   auto atrace_wrapper = std::make_unique<NiceMock<MockAtraceWrapper>>();
303 
304   auto table = FakeTable(ftrace_procfs.get());
305 
306   auto muxer =
307       FakeMuxer(ftrace_procfs.get(), atrace_wrapper.get(), table.get());
308 
309   MockFtraceProcfs* raw_procfs = ftrace_procfs.get();
310   return std::unique_ptr<TestFtraceController>(new TestFtraceController(
311       std::move(ftrace_procfs), std::move(table), std::move(atrace_wrapper),
312       std::move(muxer), std::move(runner), raw_procfs));
313 }
314 
315 }  // namespace
316 
TEST(FtraceControllerTest,NonExistentEventsDontCrash)317 TEST(FtraceControllerTest, NonExistentEventsDontCrash) {
318   auto controller = CreateTestController(true /* nice procfs */);
319 
320   FtraceConfig config = CreateFtraceConfig({"not_an_event"});
321   EXPECT_TRUE(controller->AddFakeDataSource(config));
322 }
323 
TEST(FtraceControllerTest,RejectsBadEventNames)324 TEST(FtraceControllerTest, RejectsBadEventNames) {
325   auto controller = CreateTestController(true /* nice procfs */);
326 
327   FtraceConfig config = CreateFtraceConfig({"../try/to/escape"});
328   EXPECT_FALSE(controller->AddFakeDataSource(config));
329   config = CreateFtraceConfig({"/event"});
330   EXPECT_FALSE(controller->AddFakeDataSource(config));
331   config = CreateFtraceConfig({"event/"});
332   EXPECT_FALSE(controller->AddFakeDataSource(config));
333 }
334 
TEST(FtraceControllerTest,OneSink)335 TEST(FtraceControllerTest, OneSink) {
336   auto controller = CreateTestController(false /* nice procfs */);
337 
338   // No read tasks posted as part of adding the data source.
339   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
340 
341   FtraceConfig config = CreateFtraceConfig({"group/foo"});
342 
343   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
344   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
345   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
346       .WillOnce(Return(true));
347   EXPECT_CALL(*controller->procfs(),
348               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
349       .WillRepeatedly(Return(true));
350   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _));
351   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1"));
352 
353   auto data_source = controller->AddFakeDataSource(config);
354   ASSERT_TRUE(data_source);
355 
356   // Verify that no read tasks have been posted. And set up expectation that
357   // a single recurring read task will be posted as part of starting the data
358   // source.
359   Mock::VerifyAndClearExpectations(controller->runner());
360   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
361       .WillRepeatedly(Return(true));
362 
363   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(1);
364   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
365   ASSERT_TRUE(controller->StartDataSource(data_source.get()));
366 
367   // Verify single posted read task.
368   Mock::VerifyAndClearExpectations(controller->runner());
369 
370   // State clearing on tracing teardown.
371   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0"));
372   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
373   EXPECT_CALL(*controller->procfs(),
374               WriteToFile("/root/buffer_size_kb", PageSizeKb()));
375   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
376   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
377       .WillOnce(Return(true));
378   EXPECT_CALL(*controller->procfs(),
379               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
380       .WillRepeatedly(Return(true));
381   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
382 
383   data_source.reset();
384   EXPECT_TRUE(controller->procfs()->is_tracing_on());
385 }
386 
TEST(FtraceControllerTest,MultipleSinks)387 TEST(FtraceControllerTest, MultipleSinks) {
388   auto controller = CreateTestController(false /* nice procfs */);
389 
390   FtraceConfig configA = CreateFtraceConfig({"group/foo"});
391   FtraceConfig configB = CreateFtraceConfig({"group/foo", "group/bar"});
392 
393   // No read tasks posted as part of adding the data sources.
394   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
395 
396   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
397   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
398   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
399       .WillOnce(Return(true));
400   EXPECT_CALL(*controller->procfs(),
401               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
402       .WillRepeatedly(Return(true));
403   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _));
404   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1"));
405   auto data_sourceA = controller->AddFakeDataSource(configA);
406   EXPECT_CALL(*controller->procfs(), WriteToFile(kBarEnablePath, "1"));
407   auto data_sourceB = controller->AddFakeDataSource(configB);
408 
409   // Verify that no read tasks have been posted. And set up expectation that
410   // a single recurring read task will be posted as part of starting the data
411   // sources.
412   Mock::VerifyAndClearExpectations(controller->runner());
413   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
414       .WillRepeatedly(Return(true));
415 
416   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(1);
417   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
418   ASSERT_TRUE(controller->StartDataSource(data_sourceA.get()));
419   ASSERT_TRUE(controller->StartDataSource(data_sourceB.get()));
420 
421   // Verify single posted read task.
422   Mock::VerifyAndClearExpectations(controller->runner());
423 
424   data_sourceA.reset();
425   EXPECT_TRUE(controller->procfs()->is_tracing_on());
426 
427   // State clearing on tracing teardown.
428   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0"));
429   EXPECT_CALL(*controller->procfs(), WriteToFile(kBarEnablePath, "0"));
430   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
431   EXPECT_CALL(*controller->procfs(),
432               WriteToFile("/root/buffer_size_kb", PageSizeKb()));
433   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
434   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
435       .WillOnce(Return(true));
436   EXPECT_CALL(*controller->procfs(),
437               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
438       .WillRepeatedly(Return(true));
439   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
440   data_sourceB.reset();
441   EXPECT_TRUE(controller->procfs()->is_tracing_on());
442 }
443 
TEST(FtraceControllerTest,ControllerMayDieFirst)444 TEST(FtraceControllerTest, ControllerMayDieFirst) {
445   auto controller = CreateTestController(false /* nice procfs */);
446 
447   FtraceConfig config = CreateFtraceConfig({"group/foo"});
448 
449   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
450   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
451   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
452       .WillOnce(Return(true));
453   EXPECT_CALL(*controller->procfs(),
454               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
455       .WillRepeatedly(Return(true));
456   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _));
457   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1"));
458   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
459       .WillRepeatedly(Return(true));
460   auto data_source = controller->AddFakeDataSource(config);
461 
462   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
463   ASSERT_TRUE(controller->StartDataSource(data_source.get()));
464 
465   // State clearing on tracing teardown.
466   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0"));
467   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
468   EXPECT_CALL(*controller->procfs(),
469               WriteToFile("/root/buffer_size_kb", PageSizeKb()));
470   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
471   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
472       .WillOnce(Return(true));
473   EXPECT_CALL(*controller->procfs(),
474               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
475       .WillRepeatedly(Return(true));
476   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
477   controller.reset();
478   data_source.reset();
479 }
480 
TEST(FtraceControllerTest,BufferSize)481 TEST(FtraceControllerTest, BufferSize) {
482   auto controller = CreateTestController(false /* nice procfs */);
483 
484   // For this test we don't care about most calls to WriteToFile/ClearFile.
485   EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
486   EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber());
487 
488   // Every time a fake data source is destroyed, the controller will reset the
489   // buffer size to a single page.
490   EXPECT_CALL(*controller->procfs(),
491               WriteToFile("/root/buffer_size_kb", PageSizeKb()))
492       .Times(AnyNumber());
493 
494   {
495     // No buffer size -> good default (exact value depends on the ram size of
496     // the machine running this test).
497     EXPECT_CALL(
498         *controller->procfs(),
499         WriteToFile("/root/buffer_size_kb", testing::AnyOf("2048", "8192")));
500     FtraceConfig config = CreateFtraceConfig({"group/foo"});
501     auto data_source = controller->AddFakeDataSource(config);
502     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
503   }
504 
505   {
506     // Your size ends up with less than 1 page per cpu -> 1 page (gmock already
507     // covered by the cleanup expectation above).
508     FtraceConfig config = CreateFtraceConfig({"group/foo"});
509     config.set_buffer_size_kb(1);
510     auto data_source = controller->AddFakeDataSource(config);
511     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
512   }
513 
514   {
515     // You picked a good size -> your size rounded to nearest page.
516     EXPECT_CALL(*controller->procfs(),
517                 WriteToFile("/root/buffer_size_kb", "64"));
518     FtraceConfig config = CreateFtraceConfig({"group/foo"});
519     config.set_buffer_size_kb(65);
520     auto data_source = controller->AddFakeDataSource(config);
521     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
522   }
523 
524   {
525     // You picked a good size -> your size rounded to nearest page.
526     EXPECT_CALL(*controller->procfs(),
527                 WriteToFile("/root/buffer_size_kb", "64"));
528     FtraceConfig config = CreateFtraceConfig({"group/foo"});
529     ON_CALL(*controller->procfs(), NumberOfCpus()).WillByDefault(Return(2));
530     config.set_buffer_size_kb(65);
531     auto data_source = controller->AddFakeDataSource(config);
532     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
533   }
534 
535   {
536     // buffer_size_lower_bound -> default size no less than given.
537     EXPECT_CALL(
538         *controller->procfs(),
539         WriteToFile("/root/buffer_size_kb", testing::AnyOf("4096", "8192")));
540     FtraceConfig config = CreateFtraceConfig({"group/foo"});
541     config.set_buffer_size_kb(4096);
542     config.set_buffer_size_lower_bound(true);
543     auto data_source = controller->AddFakeDataSource(config);
544     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
545   }
546 }
547 
TEST(FtraceControllerTest,PeriodicDrainConfig)548 TEST(FtraceControllerTest, PeriodicDrainConfig) {
549   auto controller = CreateTestController(false /* nice procfs */);
550 
551   // For this test we don't care about calls to WriteToFile/ClearFile.
552   EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
553   EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber());
554 
555   {
556     // No period -> good default.
557     FtraceConfig config = CreateFtraceConfig({"group/foo"});
558     auto data_source = controller->AddFakeDataSource(config);
559     controller->StartDataSource(data_source.get());
560     EXPECT_EQ(100u, controller->tick_period_ms());
561   }
562 
563   {
564     // Pick a tiny value -> good default.
565     FtraceConfig config = CreateFtraceConfig({"group/foo"});
566     config.set_drain_period_ms(0);
567     auto data_source = controller->AddFakeDataSource(config);
568     controller->StartDataSource(data_source.get());
569     EXPECT_EQ(100u, controller->tick_period_ms());
570   }
571 
572   {
573     // Pick a huge value -> good default.
574     FtraceConfig config = CreateFtraceConfig({"group/foo"});
575     config.set_drain_period_ms(1000 * 60 * 60);
576     auto data_source = controller->AddFakeDataSource(config);
577     controller->StartDataSource(data_source.get());
578     EXPECT_EQ(100u, controller->tick_period_ms());
579   }
580 
581   {
582     // Pick a resonable value -> get that value.
583     FtraceConfig config = CreateFtraceConfig({"group/foo"});
584     config.set_drain_period_ms(200);
585     auto data_source = controller->AddFakeDataSource(config);
586     controller->StartDataSource(data_source.get());
587     EXPECT_EQ(200u, controller->tick_period_ms());
588   }
589 }
590 
TEST(FtraceMetadataTest,Clear)591 TEST(FtraceMetadataTest, Clear) {
592   FtraceMetadata metadata;
593   metadata.inode_and_device.insert(std::make_pair(1, 1));
594   metadata.pids.insert(2);
595   metadata.last_seen_device_id = 100;
596   metadata.Clear();
597   EXPECT_THAT(metadata.inode_and_device, IsEmpty());
598   EXPECT_THAT(metadata.pids, IsEmpty());
599   EXPECT_EQ(BlockDeviceID(0), metadata.last_seen_device_id);
600 }
601 
TEST(FtraceMetadataTest,AddDevice)602 TEST(FtraceMetadataTest, AddDevice) {
603   FtraceMetadata metadata;
604   metadata.AddDevice(1);
605   EXPECT_EQ(BlockDeviceID(1), metadata.last_seen_device_id);
606   metadata.AddDevice(3);
607   EXPECT_EQ(BlockDeviceID(3), metadata.last_seen_device_id);
608 }
609 
TEST(FtraceMetadataTest,AddInode)610 TEST(FtraceMetadataTest, AddInode) {
611   FtraceMetadata metadata;
612   metadata.AddCommonPid(getpid() + 1);
613   metadata.AddDevice(3);
614   metadata.AddInode(2);
615   metadata.AddInode(1);
616   metadata.AddCommonPid(getpid() + 1);
617   metadata.AddDevice(4);
618   metadata.AddInode(3);
619 
620   // Check activity from ourselves is excluded.
621   metadata.AddCommonPid(getpid());
622   metadata.AddDevice(5);
623   metadata.AddInode(5);
624 
625   EXPECT_THAT(metadata.inode_and_device,
626               UnorderedElementsAre(Pair(2, 3), Pair(1, 3), Pair(3, 4)));
627 }
628 
TEST(FtraceMetadataTest,AddPid)629 TEST(FtraceMetadataTest, AddPid) {
630   FtraceMetadata metadata;
631   metadata.AddPid(1);
632   metadata.AddPid(2);
633   metadata.AddPid(2);
634   metadata.AddPid(3);
635   EXPECT_THAT(metadata.pids, ElementsAre(1, 2, 3));
636 }
637 
TEST(FtraceStatsTest,Write)638 TEST(FtraceStatsTest, Write) {
639   FtraceStats stats{};
640   FtraceCpuStats cpu_stats{};
641   cpu_stats.cpu = 0;
642   cpu_stats.entries = 1;
643   cpu_stats.overrun = 2;
644   stats.cpu_stats.push_back(cpu_stats);
645 
646   std::unique_ptr<TraceWriterForTesting> writer =
647       std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
648   {
649     auto packet = writer->NewTracePacket();
650     auto* out = packet->set_ftrace_stats();
651     stats.Write(out);
652   }
653 
654   protos::gen::TracePacket result_packet = writer->GetOnlyTracePacket();
655   auto result = result_packet.ftrace_stats().cpu_stats()[0];
656   EXPECT_EQ(result.cpu(), 0u);
657   EXPECT_EQ(result.entries(), 1u);
658   EXPECT_EQ(result.overrun(), 2u);
659   auto kprobe_stats = result_packet.ftrace_stats().kprobe_stats();
660   EXPECT_EQ(kprobe_stats.hits(), 0u);
661   EXPECT_EQ(kprobe_stats.misses(), 0u);
662 }
663 
TEST(FtraceStatsTest,WriteKprobeStats)664 TEST(FtraceStatsTest, WriteKprobeStats) {
665   FtraceStats stats{};
666   FtraceKprobeStats kprobe_stats{};
667   kprobe_stats.hits = 1;
668   kprobe_stats.misses = 2;
669   stats.kprobe_stats = kprobe_stats;
670 
671   std::unique_ptr<TraceWriterForTesting> writer =
672       std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
673   {
674     auto packet = writer->NewTracePacket();
675     auto* out = packet->set_ftrace_stats();
676     stats.Write(out);
677   }
678 
679   protos::gen::TracePacket result_packet = writer->GetOnlyTracePacket();
680   auto result = result_packet.ftrace_stats();
681   EXPECT_EQ(result.kprobe_stats().hits(), 1u);
682   EXPECT_EQ(result.kprobe_stats().misses(), 2u);
683 }
684 
TEST(FtraceStatsTest,KprobeProfileParseEmpty)685 TEST(FtraceStatsTest, KprobeProfileParseEmpty) {
686   std::string text = "";
687 
688   FtraceStats stats{};
689   EXPECT_TRUE(DumpKprobeStats(text, &stats));
690 }
691 
TEST(FtraceStatsTest,KprobeProfileParseEmptyLines)692 TEST(FtraceStatsTest, KprobeProfileParseEmptyLines) {
693   std::string text = R"(
694 
695 )";
696 
697   FtraceStats stats{};
698   EXPECT_TRUE(DumpKprobeStats(text, &stats));
699 }
700 
TEST(FtraceStatsTest,KprobeProfileParseValid)701 TEST(FtraceStatsTest, KprobeProfileParseValid) {
702   std::string text = R"(  _binder_inner_proc_lock  1   8
703   _binder_inner_proc_unlock                        2   9
704   _binder_node_inner_unlock                        3  10
705   _binder_node_unlock                              4  11
706 )";
707 
708   FtraceStats stats{};
709   EXPECT_TRUE(DumpKprobeStats(text, &stats));
710 
711   EXPECT_EQ(stats.kprobe_stats.hits, 10u);
712   EXPECT_EQ(stats.kprobe_stats.misses, 38u);
713 }
714 
TEST(FtraceStatsTest,KprobeProfileMissingValuesParseInvalid)715 TEST(FtraceStatsTest, KprobeProfileMissingValuesParseInvalid) {
716   std::string text = R"(  _binder_inner_proc_lock  1   8
717   _binder_inner_proc_unlock                        2
718 )";
719 
720   FtraceStats stats{};
721   EXPECT_FALSE(DumpKprobeStats(text, &stats));
722 
723   EXPECT_EQ(stats.kprobe_stats.hits, 0u);
724   EXPECT_EQ(stats.kprobe_stats.misses, 0u);
725 }
726 
TEST(FtraceControllerTest,OnlySecondaryInstance)727 TEST(FtraceControllerTest, OnlySecondaryInstance) {
728   auto controller = CreateTestController(true /* nice procfs */);
729 
730   FtraceConfig config = CreateFtraceConfig({"group/foo"});
731   config.set_instance_name("secondary");
732 
733   // Primary instance won't be touched throughout the entire test.
734   // Exception: allow testing for kernel support of buffer_percent.
735   EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(0);
736   EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(0);
737   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
738       .Times(AnyNumber())
739       .WillRepeatedly(Return(true));
740 
741   // AddDataSource will initialise the tracefs instance, enable the event
742   // through the muxer, but not yet enable tracing_on.
743   auto secondary_procfs = std::unique_ptr<MockFtraceProcfs>(
744       new NiceMock<MockFtraceProcfs>("/root/instances/secondary/", 1));
745   EXPECT_CALL(*secondary_procfs, WriteToFile(_, _)).Times(AnyNumber());
746   EXPECT_CALL(*secondary_procfs,
747               WriteToFile("/root/instances/secondary/tracing_on", "0"));
748   EXPECT_CALL(
749       *secondary_procfs,
750       WriteToFile("/root/instances/secondary/events/group/foo/enable", "1"));
751   controller->PrepareMockProcfsForInstance("secondary",
752                                            std::move(secondary_procfs));
753 
754   // No read tasks posted as part of adding the data source.
755   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
756 
757   std::unique_ptr<FtraceDataSource> data_source =
758       controller->AddFakeDataSource(config);
759   ASSERT_NE(nullptr, data_source);
760 
761   Mock::VerifyAndClearExpectations(
762       controller->GetInstanceMockProcfs("secondary"));
763   Mock::VerifyAndClearExpectations(controller->runner());
764 
765   // StartDataSource will simply enable the event and post a ReadTick.
766   EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
767               WriteToFile("/root/instances/secondary/tracing_on", "1"));
768   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(1);
769 
770   ASSERT_TRUE(controller->StartDataSource(data_source.get()));
771 
772   Mock::VerifyAndClearExpectations(
773       controller->GetInstanceMockProcfs("secondary"));
774   Mock::VerifyAndClearExpectations(controller->runner());
775 
776   // RemoveDataSource will reset the tracefs instance.
777   EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
778               WriteToFile(_, _))
779       .Times(AnyNumber());
780   EXPECT_CALL(
781       *controller->GetInstanceMockProcfs("secondary"),
782       WriteToFile("/root/instances/secondary/events/group/foo/enable", "0"));
783   EXPECT_CALL(
784       *controller->GetInstanceMockProcfs("secondary"),
785       WriteToFile("/root/instances/secondary/buffer_size_kb", PageSizeKb()));
786 
787   controller->RemoveDataSource(data_source.get());
788 
789   // Controller forgot about the instance.
790   EXPECT_FALSE(controller->InstanceExists("secondary"));
791 }
792 
TEST(FtraceControllerTest,DefaultAndSecondaryInstance)793 TEST(FtraceControllerTest, DefaultAndSecondaryInstance) {
794   auto controller = CreateTestController(true /* nice procfs */);
795 
796   FtraceConfig primary_cfg = CreateFtraceConfig({"group/foo"});
797   FtraceConfig secondary_cfg = CreateFtraceConfig({"group/bar"});
798   secondary_cfg.set_instance_name("secondary");
799 
800   // AddDataSource will initialise the tracefs instances, enable the events
801   // through the muxers, but not yet enable tracing_on.
802   EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
803   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
804   EXPECT_CALL(*controller->procfs(),
805               WriteToFile("/root/events/group/foo/enable", "1"));
806 
807   auto secondary_procfs = std::unique_ptr<MockFtraceProcfs>(
808       new NiceMock<MockFtraceProcfs>("/root/instances/secondary/", 1));
809   EXPECT_CALL(*secondary_procfs, WriteToFile(_, _)).Times(AnyNumber());
810   EXPECT_CALL(*secondary_procfs,
811               WriteToFile("/root/instances/secondary/tracing_on", "0"));
812   EXPECT_CALL(
813       *secondary_procfs,
814       WriteToFile("/root/instances/secondary/events/group/bar/enable", "1"));
815   controller->PrepareMockProcfsForInstance("secondary",
816                                            std::move(secondary_procfs));
817 
818   // No read tasks posted as part of adding the data sources.
819   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
820 
821   std::unique_ptr<FtraceDataSource> primary_ds =
822       controller->AddFakeDataSource(primary_cfg);
823   std::unique_ptr<FtraceDataSource> secondary_ds =
824       controller->AddFakeDataSource(secondary_cfg);
825   ASSERT_NE(nullptr, primary_ds);
826   ASSERT_NE(nullptr, secondary_ds);
827   ASSERT_NE(primary_ds->config_id(), secondary_ds->config_id());
828 
829   Mock::VerifyAndClearExpectations(controller->procfs());
830   Mock::VerifyAndClearExpectations(
831       controller->GetInstanceMockProcfs("secondary"));
832   Mock::VerifyAndClearExpectations(controller->runner());
833 
834   // StartDataSource will simply enable the events and post two ReadTicks (one
835   // per instance having the first data source activated), with the first tick
836   // becoming obsolete.
837   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
838   EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
839               WriteToFile("/root/instances/secondary/tracing_on", "1"));
840   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
841       .WillRepeatedly(Return(true));
842   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(2);
843 
844   ASSERT_TRUE(controller->StartDataSource(primary_ds.get()));
845   ASSERT_TRUE(controller->StartDataSource(secondary_ds.get()));
846 
847   Mock::VerifyAndClearExpectations(controller->procfs());
848   Mock::VerifyAndClearExpectations(
849       controller->GetInstanceMockProcfs("secondary"));
850   Mock::VerifyAndClearExpectations(controller->runner());
851 
852   // RemoveDataSource will reset the tracefs instances.
853   EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
854   EXPECT_CALL(*controller->procfs(),
855               WriteToFile("/root/events/group/foo/enable", "0"));
856 
857   EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
858               WriteToFile(_, _))
859       .Times(AnyNumber());
860   EXPECT_CALL(
861       *controller->GetInstanceMockProcfs("secondary"),
862       WriteToFile("/root/instances/secondary/events/group/bar/enable", "0"));
863 
864   controller->RemoveDataSource(primary_ds.get());
865   controller->RemoveDataSource(secondary_ds.get());
866 
867   // Controller forgot about the secondary instance.
868   EXPECT_FALSE(controller->InstanceExists("secondary"));
869 }
870 
TEST(FtraceControllerTest,TracefsInstanceFilepaths)871 TEST(FtraceControllerTest, TracefsInstanceFilepaths) {
872   std::optional<std::string> path;
873   path = FtraceController::AbsolutePathForInstance("/root/", "test");
874   EXPECT_EQ(*path, "/root/instances/test/");
875 
876   // named directory should stay under instances/
877   path = FtraceController::AbsolutePathForInstance("/root/", "test/test");
878   EXPECT_FALSE(path.has_value());
879   path = FtraceController::AbsolutePathForInstance("/root/", "..");
880   EXPECT_FALSE(path.has_value());
881 
882   // special-cased pkvm path
883   path = FtraceController::AbsolutePathForInstance("/root/", "hyp");
884   EXPECT_EQ(*path, "/root/hyp/");
885 }
886 
TEST(FtraceControllerTest,PollSupportedOnKernelVersion)887 TEST(FtraceControllerTest, PollSupportedOnKernelVersion) {
888   auto test = [](auto s) {
889     return FtraceController::PollSupportedOnKernelVersion(s);
890   };
891   // Linux 6.9 or above are ok
892   EXPECT_TRUE(test("6.9.13-1-amd64"));
893   EXPECT_TRUE(test("6.9.0-1-amd64"));
894   EXPECT_TRUE(test("6.9.25-android14-11-g"));
895   // before 6.9
896   EXPECT_FALSE(test("5.15.200-1-amd"));
897 
898   // Android: check allowlisted GKI versions
899 
900   // sublevel matters:
901   EXPECT_TRUE(test("6.1.87-android14-4-0"));
902   EXPECT_FALSE(test("6.1.80-android14-4-0"));
903   // sublevel matters:
904   EXPECT_TRUE(test("6.6.27-android15-8-suffix"));
905   EXPECT_FALSE(test("6.6.26-android15-8-suffix"));
906   // android13 instead of android14 (clarification: this is part of the kernel
907   // version, and is unrelated to the system image version).
908   EXPECT_FALSE(test("6.1.87-android13-4-0"));
909 }
910 
911 }  // namespace perfetto
912