blob: 2e2ec579f3eddf3cbccbc69620360edea223ea0c [file] [log] [blame]
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "perfetto/ftrace_reader/ftrace_controller.h"
18
19#include <fcntl.h>
20#include <stdint.h>
21#include <string.h>
22#include <sys/stat.h>
23#include <sys/types.h>
Hector Dearmanc61e8832018-01-25 12:10:12 +000024#include <sys/wait.h>
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000025
26#include <array>
27#include <string>
28
29#include "cpu_reader.h"
Hector Dearman83d98032017-12-11 16:37:43 +000030#include "event_info.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000031#include "ftrace_procfs.h"
Hector Dearmanc61e8832018-01-25 12:10:12 +000032#include "perfetto/base/build_config.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000033#include "perfetto/base/logging.h"
34#include "perfetto/base/utils.h"
35#include "proto_translation_table.h"
36
Primiano Tucci20b760c2018-01-19 12:36:12 +000037#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000038
39namespace perfetto {
40namespace {
41
Isabelle Taylorc31a4312018-01-22 16:44:28 +000042#if BUILDFLAG(OS_ANDROID)
43const char* kTracingPaths[] = {
44 "/sys/kernel/tracing/", "/sys/kernel/debug/tracing/", nullptr,
45};
46#else
47const char* kTracingPaths[] = {
48 "/sys/kernel/debug/tracing/", nullptr,
49};
50#endif
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000051
Hector Dearman6ea67b32018-02-01 15:45:15 +000052const int kDefaultDrainPeriodMs = 100;
53const int kMinDrainPeriodMs = 1;
54const int kMaxDrainPeriodMs = 1000 * 60;
55
Hector Dearmanaa9ecf62018-02-07 10:48:42 +000056const int kDefaultTotalBufferSizeKb = 1024 * 4; // 4mb
57const int kMaxTotalBufferSizeKb = 1024 * 8; // 8mb
Hector Dearman6ea67b32018-02-01 15:45:15 +000058
59uint32_t ClampDrainPeriodMs(uint32_t drain_period_ms) {
60 if (drain_period_ms == 0) {
61 return kDefaultDrainPeriodMs;
62 }
63 if (drain_period_ms < kMinDrainPeriodMs ||
64 kMaxDrainPeriodMs < drain_period_ms) {
65 PERFETTO_LOG("drain_period_ms was %u should be between %u and %u",
66 drain_period_ms, kMinDrainPeriodMs, kMaxDrainPeriodMs);
67 return kDefaultDrainPeriodMs;
68 }
69 return drain_period_ms;
70}
71
72// Post-conditions:
73// 1. result >= 1 (should have at least one page per CPU)
Hector Dearmandbdec972018-02-02 16:31:42 +000074// 2. result * 4 < kMaxTotalBufferSizeKb
Hector Dearman6ea67b32018-02-01 15:45:15 +000075// 3. If input is 0 output is a good default number.
Hector Dearmandbdec972018-02-02 16:31:42 +000076size_t ComputeCpuBufferSizeInPages(uint32_t requested_buffer_size_kb) {
Hector Dearman6ea67b32018-02-01 15:45:15 +000077 if (requested_buffer_size_kb == 0)
78 requested_buffer_size_kb = kDefaultTotalBufferSizeKb;
79 if (requested_buffer_size_kb > kMaxTotalBufferSizeKb)
80 requested_buffer_size_kb = kDefaultTotalBufferSizeKb;
81
Hector Dearmandbdec972018-02-02 16:31:42 +000082 size_t pages = requested_buffer_size_kb / (base::kPageSize / 1024);
Hector Dearman6ea67b32018-02-01 15:45:15 +000083 if (pages == 0)
84 return 1;
85
86 return pages;
87}
Hector Dearman680a28b2018-01-11 18:34:24 +000088
Hector Dearmanc61e8832018-01-25 12:10:12 +000089bool RunAtrace(std::vector<std::string> args) {
90 int status = 1;
91
92 std::vector<char*> argv;
93 // args, and then a null.
94 argv.reserve(1 + args.size());
95 for (const auto& arg : args)
96 argv.push_back(const_cast<char*>(arg.c_str()));
97 argv.push_back(nullptr);
98
99 pid_t pid = fork();
100 PERFETTO_CHECK(pid >= 0);
101 if (pid == 0) {
102 execv("/system/bin/atrace", &argv[0]);
103 // Reached only if execv fails.
104 _exit(1);
105 }
106 waitpid(pid, &status, 0);
107 return status == 0;
108}
109
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000110} // namespace
111
112// static
Isabelle Taylorc31a4312018-01-22 16:44:28 +0000113// TODO(taylori): Add a test for tracing paths in integration tests.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000114std::unique_ptr<FtraceController> FtraceController::Create(
115 base::TaskRunner* runner) {
Isabelle Taylorc31a4312018-01-22 16:44:28 +0000116 size_t index = 0;
117 std::unique_ptr<FtraceProcfs> ftrace_procfs = nullptr;
118 while (!ftrace_procfs && kTracingPaths[index]) {
119 ftrace_procfs = FtraceProcfs::Create(kTracingPaths[index++]);
120 }
121
122 if (!ftrace_procfs) {
123 return nullptr;
124 }
125
Hector Dearman77af1332017-12-15 11:55:33 +0000126 auto table = ProtoTranslationTable::Create(
127 ftrace_procfs.get(), GetStaticEventInfo(), GetStaticCommonFieldsInfo());
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000128 return std::unique_ptr<FtraceController>(
129 new FtraceController(std::move(ftrace_procfs), runner, std::move(table)));
130}
131
132FtraceController::FtraceController(std::unique_ptr<FtraceProcfs> ftrace_procfs,
133 base::TaskRunner* task_runner,
134 std::unique_ptr<ProtoTranslationTable> table)
135 : ftrace_procfs_(std::move(ftrace_procfs)),
136 task_runner_(task_runner),
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000137 enabled_count_(table->largest_id() + 1),
Primiano Tucci68323b02017-12-18 10:54:13 +0100138 table_(std::move(table)),
139 weak_factory_(this) {}
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000140
141FtraceController::~FtraceController() {
142 for (size_t id = 1; id <= table_->largest_id(); id++) {
143 if (enabled_count_[id]) {
Hector Dearman83d98032017-12-11 16:37:43 +0000144 const Event* event = table_->GetEventById(id);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000145 ftrace_procfs_->DisableEvent(event->group, event->name);
146 }
147 }
Hector Dearman5c87a752017-12-07 12:40:04 +0000148 if (listening_for_raw_trace_data_) {
149 sinks_.clear();
150 StopIfNeeded();
151 }
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000152}
153
Hector Dearman680a28b2018-01-11 18:34:24 +0000154// static
155void FtraceController::PeriodicDrainCPU(
156 base::WeakPtr<FtraceController> weak_this,
157 size_t generation,
158 int cpu) {
159 // The controller might be gone.
160 if (!weak_this)
161 return;
162 // We might have stopped caring about events.
163 if (!weak_this->listening_for_raw_trace_data_)
164 return;
165 // We might have stopped tracing then quickly re-enabled it, in this case
166 // we don't want to end up with two periodic tasks for each CPU:
167 if (weak_this->generation_ != generation)
168 return;
169
170 bool has_more = weak_this->OnRawFtraceDataAvailable(cpu);
171 weak_this->task_runner_->PostDelayedTask(
172 std::bind(&FtraceController::PeriodicDrainCPU, weak_this, generation,
173 cpu),
Hector Dearman6ea67b32018-02-01 15:45:15 +0000174 has_more ? 0 : weak_this->GetDrainPeriodMs());
Hector Dearman680a28b2018-01-11 18:34:24 +0000175}
176
Hector Dearman5c87a752017-12-07 12:40:04 +0000177void FtraceController::StartIfNeeded() {
178 if (sinks_.size() > 1)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000179 return;
Hector Dearman5c87a752017-12-07 12:40:04 +0000180 PERFETTO_CHECK(sinks_.size() != 0);
181 PERFETTO_CHECK(!listening_for_raw_trace_data_);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000182 listening_for_raw_trace_data_ = true;
Hector Dearman6ea67b32018-02-01 15:45:15 +0000183 ftrace_procfs_->SetCpuBufferSizeInPages(GetCpuBufferSizeInPages());
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000184 ftrace_procfs_->EnableTracing();
Hector Dearman20b3c1c2018-01-15 15:34:03 +0000185 generation_++;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000186 for (size_t cpu = 0; cpu < ftrace_procfs_->NumberOfCpus(); cpu++) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000187 base::WeakPtr<FtraceController> weak_this = weak_factory_.GetWeakPtr();
Hector Dearman680a28b2018-01-11 18:34:24 +0000188 task_runner_->PostDelayedTask(std::bind(&FtraceController::PeriodicDrainCPU,
Hector Dearman20b3c1c2018-01-15 15:34:03 +0000189 weak_this, generation_, cpu),
Hector Dearman6ea67b32018-02-01 15:45:15 +0000190 GetDrainPeriodMs());
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000191 }
192}
193
Hector Dearman6ea67b32018-02-01 15:45:15 +0000194uint32_t FtraceController::GetDrainPeriodMs() {
195 if (sinks_.size() == 0)
196 return kDefaultDrainPeriodMs;
197 uint32_t min_drain_period_ms = kMaxDrainPeriodMs + 1;
198 for (const FtraceSink* sink : sinks_) {
199 if (sink->config().drain_period_ms() < min_drain_period_ms)
200 min_drain_period_ms = sink->config().drain_period_ms();
201 }
202 return ClampDrainPeriodMs(min_drain_period_ms);
203}
204
205uint32_t FtraceController::GetCpuBufferSizeInPages() {
Hector Dearmandbdec972018-02-02 16:31:42 +0000206 uint32_t max_buffer_size_kb = 0;
Hector Dearman6ea67b32018-02-01 15:45:15 +0000207 for (const FtraceSink* sink : sinks_) {
Hector Dearmandbdec972018-02-02 16:31:42 +0000208 if (sink->config().buffer_size_kb() > max_buffer_size_kb)
209 max_buffer_size_kb = sink->config().buffer_size_kb();
Hector Dearman6ea67b32018-02-01 15:45:15 +0000210 }
Hector Dearmandbdec972018-02-02 16:31:42 +0000211 return ComputeCpuBufferSizeInPages(max_buffer_size_kb);
Hector Dearman6ea67b32018-02-01 15:45:15 +0000212}
213
Hector Dearmane4cc95d2018-01-09 14:32:24 +0000214void FtraceController::ClearTrace() {
215 ftrace_procfs_->ClearTrace();
216}
217
218void FtraceController::DisableAllEvents() {
219 ftrace_procfs_->DisableAllEvents();
220}
221
222void FtraceController::WriteTraceMarker(const std::string& s) {
223 ftrace_procfs_->WriteTraceMarker(s);
224}
225
Hector Dearman5c87a752017-12-07 12:40:04 +0000226void FtraceController::StopIfNeeded() {
227 if (sinks_.size() != 0)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000228 return;
Hector Dearman5c87a752017-12-07 12:40:04 +0000229 PERFETTO_CHECK(listening_for_raw_trace_data_);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000230 listening_for_raw_trace_data_ = false;
Hector Dearman5c87a752017-12-07 12:40:04 +0000231 readers_.clear();
232 ftrace_procfs_->DisableTracing();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000233}
234
Hector Dearman680a28b2018-01-11 18:34:24 +0000235bool FtraceController::OnRawFtraceDataAvailable(size_t cpu) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000236 CpuReader* reader = GetCpuReader(cpu);
237 using BundleHandle =
238 protozero::ProtoZeroMessageHandle<protos::pbzero::FtraceEventBundle>;
239 std::array<const EventFilter*, kMaxSinks> filters{};
240 std::array<BundleHandle, kMaxSinks> bundles{};
241 size_t sink_count = sinks_.size();
242 size_t i = 0;
243 for (FtraceSink* sink : sinks_) {
244 filters[i] = sink->get_event_filter();
245 bundles[i++] = sink->GetBundleForCpu(cpu);
246 }
Hector Dearman680a28b2018-01-11 18:34:24 +0000247 bool res = reader->Drain(filters, bundles);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000248 i = 0;
249 for (FtraceSink* sink : sinks_)
250 sink->OnBundleComplete(cpu, std::move(bundles[i++]));
251 PERFETTO_DCHECK(sinks_.size() == sink_count);
Hector Dearman680a28b2018-01-11 18:34:24 +0000252 return res;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000253}
254
255CpuReader* FtraceController::GetCpuReader(size_t cpu) {
256 PERFETTO_CHECK(cpu < ftrace_procfs_->NumberOfCpus());
257 if (!readers_.count(cpu)) {
258 readers_.emplace(
259 cpu, std::unique_ptr<CpuReader>(new CpuReader(
260 table_.get(), cpu, ftrace_procfs_->OpenPipeForCpu(cpu))));
261 }
262 return readers_.at(cpu).get();
263}
264
265std::unique_ptr<FtraceSink> FtraceController::CreateSink(
Hector Dearmancb4ba322018-02-09 14:12:27 +0000266 FtraceConfig config,
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000267 FtraceSink::Delegate* delegate) {
268 PERFETTO_DCHECK_THREAD(thread_checker_);
269 if (sinks_.size() >= kMaxSinks)
270 return nullptr;
Hector Dearmancb4ba322018-02-09 14:12:27 +0000271 if (!ValidConfig(config))
272 return nullptr;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000273 auto controller_weak = weak_factory_.GetWeakPtr();
Hector Dearman6ea67b32018-02-01 15:45:15 +0000274 auto filter = std::unique_ptr<EventFilter>(
Hector Dearmancb4ba322018-02-09 14:12:27 +0000275 new EventFilter(*table_.get(), FtraceEventsAsSet(config)));
276 for (const std::string& event : config.event_names())
277 PERFETTO_LOG("%s", event.c_str());
Hector Dearman6ea67b32018-02-01 15:45:15 +0000278 auto sink = std::unique_ptr<FtraceSink>(new FtraceSink(
279 std::move(controller_weak), config, std::move(filter), delegate));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000280 Register(sink.get());
281 return sink;
282}
283
284void FtraceController::Register(FtraceSink* sink) {
285 PERFETTO_DCHECK_THREAD(thread_checker_);
286 auto it_and_inserted = sinks_.insert(sink);
287 PERFETTO_DCHECK(it_and_inserted.second);
Hector Dearmancb4ba322018-02-09 14:12:27 +0000288 if (RequiresAtrace(sink->config()))
Hector Dearmanc61e8832018-01-25 12:10:12 +0000289 StartAtrace(sink->config());
Hector Dearman5c87a752017-12-07 12:40:04 +0000290
291 StartIfNeeded();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000292 for (const std::string& name : sink->enabled_events())
293 RegisterForEvent(name);
294}
295
296void FtraceController::RegisterForEvent(const std::string& name) {
297 PERFETTO_DCHECK_THREAD(thread_checker_);
Hector Dearman83d98032017-12-11 16:37:43 +0000298 const Event* event = table_->GetEventByName(name);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000299 if (!event) {
300 PERFETTO_DLOG("Can't enable %s, event not known", name.c_str());
301 return;
302 }
303 size_t& count = enabled_count_.at(event->ftrace_event_id);
304 if (count == 0)
305 ftrace_procfs_->EnableEvent(event->group, event->name);
306 count += 1;
307}
308
309void FtraceController::UnregisterForEvent(const std::string& name) {
310 PERFETTO_DCHECK_THREAD(thread_checker_);
Hector Dearman83d98032017-12-11 16:37:43 +0000311 const Event* event = table_->GetEventByName(name);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000312 if (!event)
313 return;
314 size_t& count = enabled_count_.at(event->ftrace_event_id);
315 PERFETTO_CHECK(count > 0);
316 if (--count == 0)
317 ftrace_procfs_->DisableEvent(event->group, event->name);
318}
319
320void FtraceController::Unregister(FtraceSink* sink) {
321 PERFETTO_DCHECK_THREAD(thread_checker_);
322 size_t removed = sinks_.erase(sink);
323 PERFETTO_DCHECK(removed == 1);
Hector Dearman5c87a752017-12-07 12:40:04 +0000324
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000325 for (const std::string& name : sink->enabled_events())
326 UnregisterForEvent(name);
Hector Dearmancb4ba322018-02-09 14:12:27 +0000327 if (RequiresAtrace(sink->config()))
Hector Dearmanc61e8832018-01-25 12:10:12 +0000328 StopAtrace();
Hector Dearman5c87a752017-12-07 12:40:04 +0000329 StopIfNeeded();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000330}
331
Hector Dearmanc61e8832018-01-25 12:10:12 +0000332void FtraceController::StartAtrace(const FtraceConfig& config) {
333 PERFETTO_CHECK(atrace_running_ == false);
334 atrace_running_ = true;
335 PERFETTO_DLOG("Start atrace...");
336 std::vector<std::string> args;
337 args.push_back("atrace"); // argv0 for exec()
338 args.push_back("--async_start");
339 for (const auto& category : config.atrace_categories())
340 args.push_back(category);
341 if (!config.atrace_apps().empty()) {
342 args.push_back("-a");
343 for (const auto& app : config.atrace_apps())
344 args.push_back(app);
345 }
346
347 PERFETTO_CHECK(RunAtrace(std::move(args)));
348 PERFETTO_DLOG("...done");
349}
350
351void FtraceController::StopAtrace() {
352 PERFETTO_CHECK(atrace_running_ == true);
353 atrace_running_ = false;
354 PERFETTO_DLOG("Stop atrace...");
355 PERFETTO_CHECK(
356 RunAtrace(std::vector<std::string>({"atrace", "--async_stop"})));
357 PERFETTO_DLOG("...done");
358}
359
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000360FtraceSink::FtraceSink(base::WeakPtr<FtraceController> controller_weak,
Hector Dearmanc61e8832018-01-25 12:10:12 +0000361 FtraceConfig config,
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000362 std::unique_ptr<EventFilter> filter,
363 Delegate* delegate)
364 : controller_weak_(std::move(controller_weak)),
Hector Dearman6ea67b32018-02-01 15:45:15 +0000365 config_(config),
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000366 filter_(std::move(filter)),
367 delegate_(delegate){};
368
369FtraceSink::~FtraceSink() {
370 if (controller_weak_)
371 controller_weak_->Unregister(this);
372};
373
374const std::set<std::string>& FtraceSink::enabled_events() {
375 return filter_->enabled_names();
376}
377
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000378} // namespace perfetto