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 };
210
211 } // namespace
212
213 class TestFtraceController : public FtraceController,
214 public FtraceController::Observer {
215 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)216 TestFtraceController(std::unique_ptr<MockFtraceProcfs> ftrace_procfs,
217 std::unique_ptr<Table> table,
218 std::unique_ptr<AtraceWrapper> atrace_wrapper,
219 std::unique_ptr<FtraceConfigMuxer> muxer,
220 std::unique_ptr<MockTaskRunner> runner,
221 MockFtraceProcfs* raw_procfs)
222 : FtraceController(std::move(ftrace_procfs),
223 std::move(table),
224 std::move(atrace_wrapper),
225 std::move(muxer),
226 runner.get(),
227 /*observer=*/this),
228 runner_(std::move(runner)),
229 primary_procfs_(raw_procfs) {}
230
runner()231 MockTaskRunner* runner() { return runner_.get(); }
procfs()232 MockFtraceProcfs* procfs() { return primary_procfs_; }
tick_period_ms()233 uint32_t tick_period_ms() { return GetTickPeriodMs(); }
234
AddFakeDataSource(const FtraceConfig & cfg)235 std::unique_ptr<FtraceDataSource> AddFakeDataSource(const FtraceConfig& cfg) {
236 std::unique_ptr<FtraceDataSource> data_source(new FtraceDataSource(
237 GetWeakPtr(), 0 /* session id */, cfg, nullptr /* trace_writer */));
238 if (!AddDataSource(data_source.get()))
239 return nullptr;
240 return data_source;
241 }
242
NowMs() const243 uint64_t NowMs() const override { return 0; }
OnFtraceDataWrittenIntoDataSourceBuffers()244 void OnFtraceDataWrittenIntoDataSourceBuffers() override {}
245
InstanceExists(const std::string & instance_name)246 bool InstanceExists(const std::string& instance_name) {
247 auto* instance = GetInstance(instance_name);
248 return instance != nullptr;
249 }
250
PrepareMockProcfsForInstance(const std::string & name,std::unique_ptr<MockFtraceProcfs> fs)251 void PrepareMockProcfsForInstance(const std::string& name,
252 std::unique_ptr<MockFtraceProcfs> fs) {
253 pending_instance_procfs_[name] = std::move(fs);
254 }
255
GetInstanceMockProcfs(const std::string & instance_name)256 MockFtraceProcfs* GetInstanceMockProcfs(const std::string& instance_name) {
257 auto* instance = GetInstance(instance_name);
258 PERFETTO_CHECK(instance);
259 return reinterpret_cast<MockFtraceProcfs*>(instance->ftrace_procfs.get());
260 }
261
CreateSecondaryInstance(const std::string & instance_name)262 std::unique_ptr<FtraceInstanceState> CreateSecondaryInstance(
263 const std::string& instance_name) override {
264 auto ftrace_procfs = std::move(pending_instance_procfs_[instance_name]);
265 PERFETTO_CHECK(ftrace_procfs);
266
267 auto table = FakeTable(ftrace_procfs.get());
268 auto muxer = FakeMuxer(ftrace_procfs.get(), atrace_wrapper(), table.get());
269 return std::unique_ptr<FtraceController::FtraceInstanceState>(
270 new FtraceController::FtraceInstanceState(
271 std::move(ftrace_procfs), std::move(table), std::move(muxer)));
272 }
273
274 private:
275 TestFtraceController(const TestFtraceController&) = delete;
276 TestFtraceController& operator=(const TestFtraceController&) = delete;
277
278 std::unique_ptr<MockTaskRunner> runner_;
279 MockFtraceProcfs* primary_procfs_;
280 std::map<std::string, std::unique_ptr<MockFtraceProcfs>>
281 pending_instance_procfs_;
282 };
283
284 namespace {
285
CreateTestController(bool procfs_is_nice_mock,size_t cpu_count=1)286 std::unique_ptr<TestFtraceController> CreateTestController(
287 bool procfs_is_nice_mock,
288 size_t cpu_count = 1) {
289 std::unique_ptr<MockTaskRunner> runner =
290 std::unique_ptr<MockTaskRunner>(new NiceMock<MockTaskRunner>());
291
292 std::unique_ptr<MockFtraceProcfs> ftrace_procfs;
293 if (procfs_is_nice_mock) {
294 ftrace_procfs = std::unique_ptr<MockFtraceProcfs>(
295 new NiceMock<MockFtraceProcfs>("/root/", cpu_count));
296 } else {
297 ftrace_procfs = std::unique_ptr<MockFtraceProcfs>(
298 new MockFtraceProcfs("/root/", cpu_count));
299 }
300
301 std::unique_ptr<AtraceWrapper> atrace_wrapper;
302
303 auto table = FakeTable(ftrace_procfs.get());
304
305 auto muxer =
306 FakeMuxer(ftrace_procfs.get(), atrace_wrapper.get(), table.get());
307
308 MockFtraceProcfs* raw_procfs = ftrace_procfs.get();
309 return std::unique_ptr<TestFtraceController>(new TestFtraceController(
310 std::move(ftrace_procfs), std::move(table), std::move(atrace_wrapper),
311 std::move(muxer), std::move(runner), raw_procfs));
312 }
313
314 } // namespace
315
TEST(FtraceControllerTest,NonExistentEventsDontCrash)316 TEST(FtraceControllerTest, NonExistentEventsDontCrash) {
317 auto controller = CreateTestController(true /* nice procfs */);
318
319 FtraceConfig config = CreateFtraceConfig({"not_an_event"});
320 EXPECT_TRUE(controller->AddFakeDataSource(config));
321 }
322
TEST(FtraceControllerTest,RejectsBadEventNames)323 TEST(FtraceControllerTest, RejectsBadEventNames) {
324 auto controller = CreateTestController(true /* nice procfs */);
325
326 FtraceConfig config = CreateFtraceConfig({"../try/to/escape"});
327 EXPECT_FALSE(controller->AddFakeDataSource(config));
328 config = CreateFtraceConfig({"/event"});
329 EXPECT_FALSE(controller->AddFakeDataSource(config));
330 config = CreateFtraceConfig({"event/"});
331 EXPECT_FALSE(controller->AddFakeDataSource(config));
332 }
333
TEST(FtraceControllerTest,OneSink)334 TEST(FtraceControllerTest, OneSink) {
335 auto controller = CreateTestController(false /* nice procfs */);
336
337 // No read tasks posted as part of adding the data source.
338 EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
339
340 FtraceConfig config = CreateFtraceConfig({"group/foo"});
341
342 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
343 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
344 EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
345 .WillOnce(Return(true));
346 EXPECT_CALL(*controller->procfs(),
347 ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
348 .WillRepeatedly(Return(true));
349 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _));
350 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1"));
351
352 auto data_source = controller->AddFakeDataSource(config);
353 ASSERT_TRUE(data_source);
354
355 // Verify that no read tasks have been posted. And set up expectation that
356 // a single recurring read task will be posted as part of starting the data
357 // source.
358 Mock::VerifyAndClearExpectations(controller->runner());
359 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
360 .WillRepeatedly(Return(true));
361
362 EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(1);
363 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
364 ASSERT_TRUE(controller->StartDataSource(data_source.get()));
365
366 // Verify single posted read task.
367 Mock::VerifyAndClearExpectations(controller->runner());
368
369 // State clearing on tracing teardown.
370 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0"));
371 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
372 EXPECT_CALL(*controller->procfs(),
373 WriteToFile("/root/buffer_size_kb", PageSizeKb()));
374 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
375 EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
376 .WillOnce(Return(true));
377 EXPECT_CALL(*controller->procfs(),
378 ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
379 .WillRepeatedly(Return(true));
380 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
381
382 data_source.reset();
383 EXPECT_TRUE(controller->procfs()->is_tracing_on());
384 }
385
TEST(FtraceControllerTest,MultipleSinks)386 TEST(FtraceControllerTest, MultipleSinks) {
387 auto controller = CreateTestController(false /* nice procfs */);
388
389 FtraceConfig configA = CreateFtraceConfig({"group/foo"});
390 FtraceConfig configB = CreateFtraceConfig({"group/foo", "group/bar"});
391
392 // No read tasks posted as part of adding the data sources.
393 EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
394
395 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
396 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
397 EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
398 .WillOnce(Return(true));
399 EXPECT_CALL(*controller->procfs(),
400 ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
401 .WillRepeatedly(Return(true));
402 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _));
403 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1"));
404 auto data_sourceA = controller->AddFakeDataSource(configA);
405 EXPECT_CALL(*controller->procfs(), WriteToFile(kBarEnablePath, "1"));
406 auto data_sourceB = controller->AddFakeDataSource(configB);
407
408 // Verify that no read tasks have been posted. And set up expectation that
409 // a single recurring read task will be posted as part of starting the data
410 // sources.
411 Mock::VerifyAndClearExpectations(controller->runner());
412 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
413 .WillRepeatedly(Return(true));
414
415 EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(1);
416 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
417 ASSERT_TRUE(controller->StartDataSource(data_sourceA.get()));
418 ASSERT_TRUE(controller->StartDataSource(data_sourceB.get()));
419
420 // Verify single posted read task.
421 Mock::VerifyAndClearExpectations(controller->runner());
422
423 data_sourceA.reset();
424 EXPECT_TRUE(controller->procfs()->is_tracing_on());
425
426 // State clearing on tracing teardown.
427 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0"));
428 EXPECT_CALL(*controller->procfs(), WriteToFile(kBarEnablePath, "0"));
429 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
430 EXPECT_CALL(*controller->procfs(),
431 WriteToFile("/root/buffer_size_kb", PageSizeKb()));
432 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
433 EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
434 .WillOnce(Return(true));
435 EXPECT_CALL(*controller->procfs(),
436 ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
437 .WillRepeatedly(Return(true));
438 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
439 data_sourceB.reset();
440 EXPECT_TRUE(controller->procfs()->is_tracing_on());
441 }
442
TEST(FtraceControllerTest,ControllerMayDieFirst)443 TEST(FtraceControllerTest, ControllerMayDieFirst) {
444 auto controller = CreateTestController(false /* nice procfs */);
445
446 FtraceConfig config = CreateFtraceConfig({"group/foo"});
447
448 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
449 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
450 EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
451 .WillOnce(Return(true));
452 EXPECT_CALL(*controller->procfs(),
453 ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
454 .WillRepeatedly(Return(true));
455 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _));
456 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1"));
457 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
458 .WillRepeatedly(Return(true));
459 auto data_source = controller->AddFakeDataSource(config);
460
461 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
462 ASSERT_TRUE(controller->StartDataSource(data_source.get()));
463
464 // State clearing on tracing teardown.
465 EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0"));
466 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
467 EXPECT_CALL(*controller->procfs(),
468 WriteToFile("/root/buffer_size_kb", PageSizeKb()));
469 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
470 EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
471 .WillOnce(Return(true));
472 EXPECT_CALL(*controller->procfs(),
473 ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
474 .WillRepeatedly(Return(true));
475 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
476 controller.reset();
477 data_source.reset();
478 }
479
TEST(FtraceControllerTest,BufferSize)480 TEST(FtraceControllerTest, BufferSize) {
481 auto controller = CreateTestController(false /* nice procfs */);
482
483 // For this test we don't care about most calls to WriteToFile/ClearFile.
484 EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
485 EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber());
486
487 // Every time a fake data source is destroyed, the controller will reset the
488 // buffer size to a single page.
489 EXPECT_CALL(*controller->procfs(),
490 WriteToFile("/root/buffer_size_kb", PageSizeKb()))
491 .Times(AnyNumber());
492
493 {
494 // No buffer size -> good default (exact value depends on the ram size of
495 // the machine running this test).
496 EXPECT_CALL(
497 *controller->procfs(),
498 WriteToFile("/root/buffer_size_kb", testing::AnyOf("2048", "8192")));
499 FtraceConfig config = CreateFtraceConfig({"group/foo"});
500 auto data_source = controller->AddFakeDataSource(config);
501 ASSERT_TRUE(controller->StartDataSource(data_source.get()));
502 }
503
504 {
505 // Way too big buffer size -> max size.
506 EXPECT_CALL(*controller->procfs(),
507 WriteToFile("/root/buffer_size_kb", "65536"));
508 FtraceConfig config = CreateFtraceConfig({"group/foo"});
509 config.set_buffer_size_kb(10 * 1024 * 1024);
510 auto data_source = controller->AddFakeDataSource(config);
511 ASSERT_TRUE(controller->StartDataSource(data_source.get()));
512 }
513
514 {
515 // The limit is 64mb, 65mb is too much.
516 EXPECT_CALL(*controller->procfs(),
517 WriteToFile("/root/buffer_size_kb", "65536"));
518 FtraceConfig config = CreateFtraceConfig({"group/foo"});
519 ON_CALL(*controller->procfs(), NumberOfCpus()).WillByDefault(Return(2));
520 config.set_buffer_size_kb(65 * 1024);
521 auto data_source = controller->AddFakeDataSource(config);
522 ASSERT_TRUE(controller->StartDataSource(data_source.get()));
523 }
524
525 {
526 // Your size ends up with less than 1 page per cpu -> 1 page (gmock already
527 // covered by the cleanup expectation above).
528 FtraceConfig config = CreateFtraceConfig({"group/foo"});
529 config.set_buffer_size_kb(1);
530 auto data_source = controller->AddFakeDataSource(config);
531 ASSERT_TRUE(controller->StartDataSource(data_source.get()));
532 }
533
534 {
535 // You picked a good size -> your size rounded to nearest page.
536 EXPECT_CALL(*controller->procfs(),
537 WriteToFile("/root/buffer_size_kb", "64"));
538 FtraceConfig config = CreateFtraceConfig({"group/foo"});
539 config.set_buffer_size_kb(65);
540 auto data_source = controller->AddFakeDataSource(config);
541 ASSERT_TRUE(controller->StartDataSource(data_source.get()));
542 }
543
544 {
545 // You picked a good size -> your size rounded to nearest page.
546 EXPECT_CALL(*controller->procfs(),
547 WriteToFile("/root/buffer_size_kb", "64"));
548 FtraceConfig config = CreateFtraceConfig({"group/foo"});
549 ON_CALL(*controller->procfs(), NumberOfCpus()).WillByDefault(Return(2));
550 config.set_buffer_size_kb(65);
551 auto data_source = controller->AddFakeDataSource(config);
552 ASSERT_TRUE(controller->StartDataSource(data_source.get()));
553 }
554
555 {
556 // buffer_size_lower_bound -> default size no less than given.
557 EXPECT_CALL(
558 *controller->procfs(),
559 WriteToFile("/root/buffer_size_kb", testing::AnyOf("4096", "8192")));
560 FtraceConfig config = CreateFtraceConfig({"group/foo"});
561 config.set_buffer_size_kb(4096);
562 config.set_buffer_size_lower_bound(true);
563 auto data_source = controller->AddFakeDataSource(config);
564 ASSERT_TRUE(controller->StartDataSource(data_source.get()));
565 }
566 }
567
TEST(FtraceControllerTest,PeriodicDrainConfig)568 TEST(FtraceControllerTest, PeriodicDrainConfig) {
569 auto controller = CreateTestController(false /* nice procfs */);
570
571 // For this test we don't care about calls to WriteToFile/ClearFile.
572 EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
573 EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber());
574
575 {
576 // No period -> good default.
577 FtraceConfig config = CreateFtraceConfig({"group/foo"});
578 auto data_source = controller->AddFakeDataSource(config);
579 controller->StartDataSource(data_source.get());
580 EXPECT_EQ(100u, controller->tick_period_ms());
581 }
582
583 {
584 // Pick a tiny value -> good default.
585 FtraceConfig config = CreateFtraceConfig({"group/foo"});
586 config.set_drain_period_ms(0);
587 auto data_source = controller->AddFakeDataSource(config);
588 controller->StartDataSource(data_source.get());
589 EXPECT_EQ(100u, controller->tick_period_ms());
590 }
591
592 {
593 // Pick a huge value -> good default.
594 FtraceConfig config = CreateFtraceConfig({"group/foo"});
595 config.set_drain_period_ms(1000 * 60 * 60);
596 auto data_source = controller->AddFakeDataSource(config);
597 controller->StartDataSource(data_source.get());
598 EXPECT_EQ(100u, controller->tick_period_ms());
599 }
600
601 {
602 // Pick a resonable value -> get that value.
603 FtraceConfig config = CreateFtraceConfig({"group/foo"});
604 config.set_drain_period_ms(200);
605 auto data_source = controller->AddFakeDataSource(config);
606 controller->StartDataSource(data_source.get());
607 EXPECT_EQ(200u, controller->tick_period_ms());
608 }
609 }
610
TEST(FtraceMetadataTest,Clear)611 TEST(FtraceMetadataTest, Clear) {
612 FtraceMetadata metadata;
613 metadata.inode_and_device.insert(std::make_pair(1, 1));
614 metadata.pids.insert(2);
615 metadata.last_seen_device_id = 100;
616 metadata.Clear();
617 EXPECT_THAT(metadata.inode_and_device, IsEmpty());
618 EXPECT_THAT(metadata.pids, IsEmpty());
619 EXPECT_EQ(BlockDeviceID(0), metadata.last_seen_device_id);
620 }
621
TEST(FtraceMetadataTest,AddDevice)622 TEST(FtraceMetadataTest, AddDevice) {
623 FtraceMetadata metadata;
624 metadata.AddDevice(1);
625 EXPECT_EQ(BlockDeviceID(1), metadata.last_seen_device_id);
626 metadata.AddDevice(3);
627 EXPECT_EQ(BlockDeviceID(3), metadata.last_seen_device_id);
628 }
629
TEST(FtraceMetadataTest,AddInode)630 TEST(FtraceMetadataTest, AddInode) {
631 FtraceMetadata metadata;
632 metadata.AddCommonPid(getpid() + 1);
633 metadata.AddDevice(3);
634 metadata.AddInode(2);
635 metadata.AddInode(1);
636 metadata.AddCommonPid(getpid() + 1);
637 metadata.AddDevice(4);
638 metadata.AddInode(3);
639
640 // Check activity from ourselves is excluded.
641 metadata.AddCommonPid(getpid());
642 metadata.AddDevice(5);
643 metadata.AddInode(5);
644
645 EXPECT_THAT(metadata.inode_and_device,
646 UnorderedElementsAre(Pair(2, 3), Pair(1, 3), Pair(3, 4)));
647 }
648
TEST(FtraceMetadataTest,AddPid)649 TEST(FtraceMetadataTest, AddPid) {
650 FtraceMetadata metadata;
651 metadata.AddPid(1);
652 metadata.AddPid(2);
653 metadata.AddPid(2);
654 metadata.AddPid(3);
655 EXPECT_THAT(metadata.pids, ElementsAre(1, 2, 3));
656 }
657
TEST(FtraceStatsTest,Write)658 TEST(FtraceStatsTest, Write) {
659 FtraceStats stats{};
660 FtraceCpuStats cpu_stats{};
661 cpu_stats.cpu = 0;
662 cpu_stats.entries = 1;
663 cpu_stats.overrun = 2;
664 stats.cpu_stats.push_back(cpu_stats);
665
666 std::unique_ptr<TraceWriterForTesting> writer =
667 std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
668 {
669 auto packet = writer->NewTracePacket();
670 auto* out = packet->set_ftrace_stats();
671 stats.Write(out);
672 }
673
674 protos::gen::TracePacket result_packet = writer->GetOnlyTracePacket();
675 auto result = result_packet.ftrace_stats().cpu_stats()[0];
676 EXPECT_EQ(result.cpu(), 0u);
677 EXPECT_EQ(result.entries(), 1u);
678 EXPECT_EQ(result.overrun(), 2u);
679 }
680
TEST(FtraceControllerTest,OnlySecondaryInstance)681 TEST(FtraceControllerTest, OnlySecondaryInstance) {
682 auto controller = CreateTestController(true /* nice procfs */);
683
684 FtraceConfig config = CreateFtraceConfig({"group/foo"});
685 config.set_instance_name("secondary");
686
687 // Primary instance won't be touched throughout the entire test.
688 // Exception: allow testing for kernel support of buffer_percent.
689 EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(0);
690 EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(0);
691 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
692 .Times(AnyNumber())
693 .WillRepeatedly(Return(true));
694
695 // AddDataSource will initialise the tracefs instance, enable the event
696 // through the muxer, but not yet enable tracing_on.
697 auto secondary_procfs = std::unique_ptr<MockFtraceProcfs>(
698 new NiceMock<MockFtraceProcfs>("/root/instances/secondary/", 1));
699 EXPECT_CALL(*secondary_procfs, WriteToFile(_, _)).Times(AnyNumber());
700 EXPECT_CALL(*secondary_procfs,
701 WriteToFile("/root/instances/secondary/tracing_on", "0"));
702 EXPECT_CALL(
703 *secondary_procfs,
704 WriteToFile("/root/instances/secondary/events/group/foo/enable", "1"));
705 controller->PrepareMockProcfsForInstance("secondary",
706 std::move(secondary_procfs));
707
708 // No read tasks posted as part of adding the data source.
709 EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
710
711 std::unique_ptr<FtraceDataSource> data_source =
712 controller->AddFakeDataSource(config);
713 ASSERT_NE(nullptr, data_source);
714
715 Mock::VerifyAndClearExpectations(
716 controller->GetInstanceMockProcfs("secondary"));
717 Mock::VerifyAndClearExpectations(controller->runner());
718
719 // StartDataSource will simply enable the event and post a ReadTick.
720 EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
721 WriteToFile("/root/instances/secondary/tracing_on", "1"));
722 EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(1);
723
724 ASSERT_TRUE(controller->StartDataSource(data_source.get()));
725
726 Mock::VerifyAndClearExpectations(
727 controller->GetInstanceMockProcfs("secondary"));
728 Mock::VerifyAndClearExpectations(controller->runner());
729
730 // RemoveDataSource will reset the tracefs instance.
731 EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
732 WriteToFile(_, _))
733 .Times(AnyNumber());
734 EXPECT_CALL(
735 *controller->GetInstanceMockProcfs("secondary"),
736 WriteToFile("/root/instances/secondary/events/group/foo/enable", "0"));
737 EXPECT_CALL(
738 *controller->GetInstanceMockProcfs("secondary"),
739 WriteToFile("/root/instances/secondary/buffer_size_kb", PageSizeKb()));
740
741 controller->RemoveDataSource(data_source.get());
742
743 // Controller forgot about the instance.
744 EXPECT_FALSE(controller->InstanceExists("secondary"));
745 }
746
TEST(FtraceControllerTest,DefaultAndSecondaryInstance)747 TEST(FtraceControllerTest, DefaultAndSecondaryInstance) {
748 auto controller = CreateTestController(true /* nice procfs */);
749
750 FtraceConfig primary_cfg = CreateFtraceConfig({"group/foo"});
751 FtraceConfig secondary_cfg = CreateFtraceConfig({"group/bar"});
752 secondary_cfg.set_instance_name("secondary");
753
754 // AddDataSource will initialise the tracefs instances, enable the events
755 // through the muxers, but not yet enable tracing_on.
756 EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
757 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
758 EXPECT_CALL(*controller->procfs(),
759 WriteToFile("/root/events/group/foo/enable", "1"));
760
761 auto secondary_procfs = std::unique_ptr<MockFtraceProcfs>(
762 new NiceMock<MockFtraceProcfs>("/root/instances/secondary/", 1));
763 EXPECT_CALL(*secondary_procfs, WriteToFile(_, _)).Times(AnyNumber());
764 EXPECT_CALL(*secondary_procfs,
765 WriteToFile("/root/instances/secondary/tracing_on", "0"));
766 EXPECT_CALL(
767 *secondary_procfs,
768 WriteToFile("/root/instances/secondary/events/group/bar/enable", "1"));
769 controller->PrepareMockProcfsForInstance("secondary",
770 std::move(secondary_procfs));
771
772 // No read tasks posted as part of adding the data sources.
773 EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
774
775 std::unique_ptr<FtraceDataSource> primary_ds =
776 controller->AddFakeDataSource(primary_cfg);
777 std::unique_ptr<FtraceDataSource> secondary_ds =
778 controller->AddFakeDataSource(secondary_cfg);
779 ASSERT_NE(nullptr, primary_ds);
780 ASSERT_NE(nullptr, secondary_ds);
781 ASSERT_NE(primary_ds->config_id(), secondary_ds->config_id());
782
783 Mock::VerifyAndClearExpectations(controller->procfs());
784 Mock::VerifyAndClearExpectations(
785 controller->GetInstanceMockProcfs("secondary"));
786 Mock::VerifyAndClearExpectations(controller->runner());
787
788 // StartDataSource will simply enable the events and post two ReadTicks (one
789 // per instance having the first data source activated), with the first tick
790 // becoming obsolete.
791 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
792 EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
793 WriteToFile("/root/instances/secondary/tracing_on", "1"));
794 EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
795 .WillRepeatedly(Return(true));
796 EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(2);
797
798 ASSERT_TRUE(controller->StartDataSource(primary_ds.get()));
799 ASSERT_TRUE(controller->StartDataSource(secondary_ds.get()));
800
801 Mock::VerifyAndClearExpectations(controller->procfs());
802 Mock::VerifyAndClearExpectations(
803 controller->GetInstanceMockProcfs("secondary"));
804 Mock::VerifyAndClearExpectations(controller->runner());
805
806 // RemoveDataSource will reset the tracefs instances.
807 EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
808 EXPECT_CALL(*controller->procfs(),
809 WriteToFile("/root/events/group/foo/enable", "0"));
810
811 EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
812 WriteToFile(_, _))
813 .Times(AnyNumber());
814 EXPECT_CALL(
815 *controller->GetInstanceMockProcfs("secondary"),
816 WriteToFile("/root/instances/secondary/events/group/bar/enable", "0"));
817
818 controller->RemoveDataSource(primary_ds.get());
819 controller->RemoveDataSource(secondary_ds.get());
820
821 // Controller forgot about the secondary instance.
822 EXPECT_FALSE(controller->InstanceExists("secondary"));
823 }
824
TEST(FtraceControllerTest,TracefsInstanceFilepaths)825 TEST(FtraceControllerTest, TracefsInstanceFilepaths) {
826 std::optional<std::string> path;
827 path = FtraceController::AbsolutePathForInstance("/root/", "test");
828 EXPECT_EQ(*path, "/root/instances/test/");
829
830 // named directory should stay under instances/
831 path = FtraceController::AbsolutePathForInstance("/root/", "test/test");
832 EXPECT_FALSE(path.has_value());
833 path = FtraceController::AbsolutePathForInstance("/root/", "..");
834 EXPECT_FALSE(path.has_value());
835
836 // special-cased pkvm path
837 path = FtraceController::AbsolutePathForInstance("/root/", "hyp");
838 EXPECT_EQ(*path, "/root/hyp/");
839 }
840
TEST(FtraceControllerTest,PollSupportedOnKernelVersion)841 TEST(FtraceControllerTest, PollSupportedOnKernelVersion) {
842 auto test = [](auto s) {
843 return FtraceController::PollSupportedOnKernelVersion(s);
844 };
845 // Linux 6.1 or above are ok
846 EXPECT_TRUE(test("6.5.13-1-amd64"));
847 EXPECT_TRUE(test("6.1.0-1-amd64"));
848 EXPECT_TRUE(test("6.1.25-android14-11-g"));
849 // before 6.1
850 EXPECT_FALSE(test("5.15.200-1-amd"));
851
852 // Android: check allowlisted GKI versions
853
854 // sublevel matters:
855 EXPECT_TRUE(test("5.10.198-android13-4-0"));
856 EXPECT_FALSE(test("5.10.189-android13-4-0"));
857 // sublevel matters:
858 EXPECT_TRUE(test("5.15.137-android14-8-suffix"));
859 EXPECT_FALSE(test("5.15.130-android14-8-suffix"));
860 // sublevel matters:
861 EXPECT_TRUE(test("5.15.137-android13-8-0"));
862 EXPECT_FALSE(test("5.15.129-android13-8-0"));
863 // android12 instead of android13 (clarification: this is part of the kernel
864 // version, and is unrelated to the system image version).
865 EXPECT_FALSE(test("5.10.198-android12-4-0"));
866 }
867
868 } // namespace perfetto
869