blob: 09b22ea27b04da0f895326ff33971e35f9fb04de [file] [log] [blame]
Hector Dearman650fb842017-11-06 15:03:41 +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 "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>
24
Hector Dearman0d300332017-11-22 11:05:34 +000025#include <array>
Hector Dearman650fb842017-11-06 15:03:41 +000026#include <string>
27
Hector Dearman0d300332017-11-22 11:05:34 +000028#include "cpu_reader.h"
29#include "ftrace_procfs.h"
Oystein Eftevaagdd727e42017-12-05 08:49:55 -080030#include "perfetto_base/logging.h"
31#include "perfetto_base/utils.h"
Hector Dearman0d300332017-11-22 11:05:34 +000032#include "proto_translation_table.h"
Hector Dearman650fb842017-11-06 15:03:41 +000033
Primiano Tucci5f48d7b2017-11-27 16:57:13 +000034#include "protos/ftrace/ftrace_event_bundle.pbzero.h"
35
Hector Dearman650fb842017-11-06 15:03:41 +000036namespace perfetto {
Hector Dearman650fb842017-11-06 15:03:41 +000037namespace {
38
39// TODO(b/68242551): Do not hardcode these paths.
Hector Dearmana4cb5642017-11-15 16:35:56 +000040const char kTracingPath[] = "/sys/kernel/debug/tracing/";
41
Hector Dearman650fb842017-11-06 15:03:41 +000042} // namespace
43
Hector Dearman72a49052017-11-08 14:12:55 +000044// static
Hector Dearmana4cb5642017-11-15 16:35:56 +000045std::unique_ptr<FtraceController> FtraceController::Create(
46 base::TaskRunner* runner) {
Hector Dearman0d300332017-11-22 11:05:34 +000047 auto ftrace_procfs =
48 std::unique_ptr<FtraceProcfs>(new FtraceProcfs(kTracingPath));
Hector Dearman8d8ccd32017-11-27 16:06:34 +000049 auto table = ProtoTranslationTable::Create(ftrace_procfs.get());
Hector Dearman72a49052017-11-08 14:12:55 +000050 return std::unique_ptr<FtraceController>(
Hector Dearman0d300332017-11-22 11:05:34 +000051 new FtraceController(std::move(ftrace_procfs), runner, std::move(table)));
Hector Dearman72a49052017-11-08 14:12:55 +000052}
53
Hector Dearman0d300332017-11-22 11:05:34 +000054FtraceController::FtraceController(std::unique_ptr<FtraceProcfs> ftrace_procfs,
55 base::TaskRunner* task_runner,
56 std::unique_ptr<ProtoTranslationTable> table)
57 : ftrace_procfs_(std::move(ftrace_procfs)),
58 task_runner_(task_runner),
Hector Dearmana4cb5642017-11-15 16:35:56 +000059 weak_factory_(this),
60 enabled_count_(table->largest_id() + 1),
61 table_(std::move(table)) {}
Hector Dearman650fb842017-11-06 15:03:41 +000062
Hector Dearman0d300332017-11-22 11:05:34 +000063FtraceController::~FtraceController() {
64 for (size_t id = 1; id <= table_->largest_id(); id++) {
65 if (enabled_count_[id]) {
66 const ProtoTranslationTable::Event* event = table_->GetEventById(id);
67 ftrace_procfs_->DisableEvent(event->group, event->name);
68 }
Hector Dearman72a49052017-11-08 14:12:55 +000069 }
Hector Dearman72a49052017-11-08 14:12:55 +000070}
71
Hector Dearman0d300332017-11-22 11:05:34 +000072void FtraceController::Start() {
73 if (listening_for_raw_trace_data_) {
74 PERFETTO_DLOG("FtraceController is already started.");
75 return;
76 }
77 listening_for_raw_trace_data_ = true;
Hector Dearman8d8ccd32017-11-27 16:06:34 +000078 ftrace_procfs_->EnableTracing();
Hector Dearman0d300332017-11-22 11:05:34 +000079 for (size_t cpu = 0; cpu < ftrace_procfs_->NumberOfCpus(); cpu++) {
80 CpuReader* reader = GetCpuReader(cpu);
81 int fd = reader->GetFileDescriptor();
82 base::WeakPtr<FtraceController> weak_this = weak_factory_.GetWeakPtr();
83 task_runner_->AddFileDescriptorWatch(fd, [weak_this, cpu]() {
84 if (!weak_this) {
85 // The controller might be gone.
86 return;
87 }
88 weak_this->OnRawFtraceDataAvailable(cpu);
89 });
90 }
91}
92
93void FtraceController::Stop() {
94 if (!listening_for_raw_trace_data_) {
95 PERFETTO_DLOG("FtraceController is already stopped.");
96 return;
97 }
98 listening_for_raw_trace_data_ = false;
99 for (size_t cpu = 0; cpu < ftrace_procfs_->NumberOfCpus(); cpu++) {
100 CpuReader* reader = GetCpuReader(cpu);
101 int fd = reader->GetFileDescriptor();
102 task_runner_->RemoveFileDescriptorWatch(fd);
103 }
104}
105
106void FtraceController::OnRawFtraceDataAvailable(size_t cpu) {
107 CpuReader* reader = GetCpuReader(cpu);
108 using BundleHandle =
Primiano Tucci5f48d7b2017-11-27 16:57:13 +0000109 protozero::ProtoZeroMessageHandle<protos::pbzero::FtraceEventBundle>;
Hector Dearman0d300332017-11-22 11:05:34 +0000110 std::array<const EventFilter*, kMaxSinks> filters{};
111 std::array<BundleHandle, kMaxSinks> bundles{};
112 size_t sink_count = sinks_.size();
113 size_t i = 0;
114 for (FtraceSink* sink : sinks_) {
115 filters[i] = sink->get_event_filter();
116 bundles[i++] = sink->GetBundleForCpu(cpu);
117 }
118 reader->Drain(filters, bundles);
119 i = 0;
120 for (FtraceSink* sink : sinks_)
121 sink->OnBundleComplete(cpu, std::move(bundles[i++]));
122 PERFETTO_DCHECK(sinks_.size() == sink_count);
123}
124
125CpuReader* FtraceController::GetCpuReader(size_t cpu) {
126 PERFETTO_CHECK(cpu < ftrace_procfs_->NumberOfCpus());
127 if (!readers_.count(cpu)) {
128 readers_.emplace(
129 cpu, std::unique_ptr<CpuReader>(new CpuReader(
130 table_.get(), cpu, ftrace_procfs_->OpenPipeForCpu(cpu))));
131 }
132 return readers_.at(cpu).get();
Hector Dearman72a49052017-11-08 14:12:55 +0000133}
134
Hector Dearmana4cb5642017-11-15 16:35:56 +0000135std::unique_ptr<FtraceSink> FtraceController::CreateSink(
136 FtraceConfig config,
137 FtraceSink::Delegate* delegate) {
138 PERFETTO_DCHECK_THREAD(thread_checker_);
Hector Dearman0d300332017-11-22 11:05:34 +0000139 if (sinks_.size() >= kMaxSinks)
140 return nullptr;
Hector Dearmana4cb5642017-11-15 16:35:56 +0000141 auto controller_weak = weak_factory_.GetWeakPtr();
Hector Dearman0d300332017-11-22 11:05:34 +0000142 auto filter = std::unique_ptr<EventFilter>(
143 new EventFilter(*table_.get(), config.events()));
Hector Dearmana4cb5642017-11-15 16:35:56 +0000144 auto sink = std::unique_ptr<FtraceSink>(
Hector Dearman0d300332017-11-22 11:05:34 +0000145 new FtraceSink(std::move(controller_weak), std::move(filter), delegate));
Hector Dearmana4cb5642017-11-15 16:35:56 +0000146 Register(sink.get());
147 return sink;
148}
149
150void FtraceController::Register(FtraceSink* sink) {
151 PERFETTO_DCHECK_THREAD(thread_checker_);
152 auto it_and_inserted = sinks_.insert(sink);
153 PERFETTO_DCHECK(it_and_inserted.second);
154 for (const std::string& name : sink->enabled_events())
155 RegisterForEvent(name);
156}
157
158void FtraceController::RegisterForEvent(const std::string& name) {
159 PERFETTO_DCHECK_THREAD(thread_checker_);
Hector Dearman0d300332017-11-22 11:05:34 +0000160 const ProtoTranslationTable::Event* event = table_->GetEventByName(name);
161 if (!event) {
162 PERFETTO_DLOG("Can't enable %s, event not known", name.c_str());
Hector Dearmana4cb5642017-11-15 16:35:56 +0000163 return;
Hector Dearman0d300332017-11-22 11:05:34 +0000164 }
165 size_t& count = enabled_count_.at(event->ftrace_event_id);
Hector Dearmana4cb5642017-11-15 16:35:56 +0000166 if (count == 0)
Hector Dearman0d300332017-11-22 11:05:34 +0000167 ftrace_procfs_->EnableEvent(event->group, event->name);
Hector Dearmana4cb5642017-11-15 16:35:56 +0000168 count += 1;
169}
170
171void FtraceController::UnregisterForEvent(const std::string& name) {
172 PERFETTO_DCHECK_THREAD(thread_checker_);
Hector Dearman0d300332017-11-22 11:05:34 +0000173 const ProtoTranslationTable::Event* event = table_->GetEventByName(name);
Hector Dearmana4cb5642017-11-15 16:35:56 +0000174 if (!event)
175 return;
Hector Dearman0d300332017-11-22 11:05:34 +0000176 size_t& count = enabled_count_.at(event->ftrace_event_id);
Hector Dearmana4cb5642017-11-15 16:35:56 +0000177 PERFETTO_CHECK(count > 0);
Hector Dearman0d300332017-11-22 11:05:34 +0000178 if (--count == 0)
179 ftrace_procfs_->DisableEvent(event->group, event->name);
Hector Dearmana4cb5642017-11-15 16:35:56 +0000180}
181
182void FtraceController::Unregister(FtraceSink* sink) {
183 PERFETTO_DCHECK_THREAD(thread_checker_);
184 size_t removed = sinks_.erase(sink);
185 PERFETTO_DCHECK(removed == 1);
186 for (const std::string& name : sink->enabled_events())
187 UnregisterForEvent(name);
188}
189
190FtraceSink::FtraceSink(base::WeakPtr<FtraceController> controller_weak,
Hector Dearman0d300332017-11-22 11:05:34 +0000191 std::unique_ptr<EventFilter> filter,
192 Delegate* delegate)
Hector Dearmana4cb5642017-11-15 16:35:56 +0000193 : controller_weak_(std::move(controller_weak)),
Hector Dearman0d300332017-11-22 11:05:34 +0000194 filter_(std::move(filter)),
195 delegate_(delegate){};
Hector Dearmana4cb5642017-11-15 16:35:56 +0000196
197FtraceSink::~FtraceSink() {
198 if (controller_weak_)
199 controller_weak_->Unregister(this);
200};
201
Hector Dearman0d300332017-11-22 11:05:34 +0000202const std::set<std::string>& FtraceSink::enabled_events() {
203 return filter_->enabled_names();
204}
205
Hector Dearmana4cb5642017-11-15 16:35:56 +0000206FtraceConfig::FtraceConfig() = default;
Hector Dearman0d300332017-11-22 11:05:34 +0000207FtraceConfig::FtraceConfig(std::set<std::string> events)
208 : events_(std::move(events)) {}
Hector Dearmana4cb5642017-11-15 16:35:56 +0000209FtraceConfig::~FtraceConfig() = default;
210
211void FtraceConfig::AddEvent(const std::string& event) {
212 events_.insert(event);
213}
214
Hector Dearman650fb842017-11-06 15:03:41 +0000215} // namespace perfetto