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