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