blob: 718e51ff22c19c3bf185092095ec45fe34cb4b3a [file] [log] [blame]
Isabelle Taylord404ea12018-02-19 17:28:01 +00001/*
2 * Copyright (C) 2018 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/probes_producer.h"
18
19#include <stdio.h>
Anna Zappone27ac99c2018-03-06 14:25:35 +000020#include <queue>
Isabelle Taylord404ea12018-02-19 17:28:01 +000021#include <string>
22
23#include "perfetto/base/logging.h"
24#include "perfetto/traced/traced.h"
25#include "perfetto/tracing/core/data_source_config.h"
26#include "perfetto/tracing/core/data_source_descriptor.h"
Hector Dearmana89cc572018-02-23 12:02:58 +000027#include "perfetto/tracing/core/ftrace_config.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000028#include "perfetto/tracing/core/trace_config.h"
29#include "perfetto/tracing/core/trace_packet.h"
30
31#include "src/process_stats/file_utils.h"
32#include "src/process_stats/procfs_utils.h"
33
Anna Zappone27ac99c2018-03-06 14:25:35 +000034#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000035#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
36#include "perfetto/trace/ps/process_tree.pbzero.h"
37#include "perfetto/trace/trace_packet.pbzero.h"
38
39namespace perfetto {
40namespace {
41
42uint64_t kInitialConnectionBackoffMs = 100;
43uint64_t kMaxConnectionBackoffMs = 30 * 1000;
44const char* kFtraceSourceName = "com.google.perfetto.ftrace";
45const char* kProcessStatsSourceName = "com.google.perfetto.process_stats";
Anna Zappone27ac99c2018-03-06 14:25:35 +000046const char* kInodeFileMapSourceName = "com.google.perfetto.inode_file_map";
Isabelle Taylord404ea12018-02-19 17:28:01 +000047
48} // namespace.
49
50// State transition diagram:
51// +----------------------------+
52// v +
53// NotStarted -> NotConnected -> Connecting -> Connected
54// ^ +
55// +--------------+
56//
57
Hector Dearmanc8488032018-03-02 13:12:01 +000058ProbesProducer::ProbesProducer() {}
Isabelle Taylord404ea12018-02-19 17:28:01 +000059ProbesProducer::~ProbesProducer() = default;
60
61void ProbesProducer::OnConnect() {
62 PERFETTO_DCHECK(state_ == kConnecting);
63 state_ = kConnected;
64 ResetConnectionBackoff();
65 PERFETTO_LOG("Connected to the service");
66
67 DataSourceDescriptor ftrace_descriptor;
68 ftrace_descriptor.set_name(kFtraceSourceName);
Lalit Magantia88807d2018-03-05 18:21:38 +000069 endpoint_->RegisterDataSource(ftrace_descriptor, [](DataSourceInstanceID) {});
Isabelle Taylord404ea12018-02-19 17:28:01 +000070
71 DataSourceDescriptor process_stats_descriptor;
72 process_stats_descriptor.set_name(kProcessStatsSourceName);
73 endpoint_->RegisterDataSource(process_stats_descriptor,
Lalit Magantia88807d2018-03-05 18:21:38 +000074 [](DataSourceInstanceID) {});
Anna Zappone27ac99c2018-03-06 14:25:35 +000075
76 DataSourceDescriptor inode_map_descriptor;
77 inode_map_descriptor.set_name(kInodeFileMapSourceName);
78 endpoint_->RegisterDataSource(inode_map_descriptor,
79 [](DataSourceInstanceID) {});
Isabelle Taylord404ea12018-02-19 17:28:01 +000080}
81
82void ProbesProducer::OnDisconnect() {
83 PERFETTO_DCHECK(state_ == kConnected || state_ == kConnecting);
84 state_ = kNotConnected;
85 PERFETTO_LOG("Disconnected from tracing service");
86 IncreaseConnectionBackoff();
87
88 // TODO(hjd): Erase all sinks and add e2e test for this.
89 task_runner_->PostDelayedTask([this] { this->Connect(); },
90 connection_backoff_ms_);
91}
92
93void ProbesProducer::CreateDataSourceInstance(
94 DataSourceInstanceID id,
95 const DataSourceConfig& source_config) {
96 instances_[id] = source_config.name();
Isabelle Taylord404ea12018-02-19 17:28:01 +000097 if (source_config.name() == kFtraceSourceName) {
98 CreateFtraceDataSourceInstance(id, source_config);
99 } else if (source_config.name() == kProcessStatsSourceName) {
100 CreateProcessStatsDataSourceInstance(source_config);
Anna Zappone27ac99c2018-03-06 14:25:35 +0000101 } else if (source_config.name() == kInodeFileMapSourceName) {
102 CreateInodeFileMapDataSourceInstance(id, source_config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000103 } else {
104 PERFETTO_ELOG("Data source name: %s not recognised.",
105 source_config.name().c_str());
106 }
107}
108
Anna Zappone27ac99c2018-03-06 14:25:35 +0000109void ProbesProducer::AddWatchdogsTimer(DataSourceInstanceID id,
110 const DataSourceConfig& source_config) {
111 if (source_config.trace_duration_ms() != 0)
112 watchdogs_.emplace(id, base::Watchdog::GetInstance()->CreateFatalTimer(
113 5000 + 2 * source_config.trace_duration_ms()));
114}
115
Isabelle Taylord404ea12018-02-19 17:28:01 +0000116void ProbesProducer::CreateFtraceDataSourceInstance(
117 DataSourceInstanceID id,
118 const DataSourceConfig& source_config) {
119 // Don't retry if FtraceController::Create() failed once.
120 // This can legitimately happen on user builds where we cannot access the
121 // debug paths, e.g., because of SELinux rules.
122 if (ftrace_creation_failed_)
123 return;
124
125 // Lazily create on the first instance.
126 if (!ftrace_) {
127 ftrace_ = FtraceController::Create(task_runner_);
128
129 if (!ftrace_) {
130 PERFETTO_ELOG("Failed to create FtraceController");
131 ftrace_creation_failed_ = true;
132 return;
133 }
134
135 ftrace_->DisableAllEvents();
136 ftrace_->ClearTrace();
137 }
138
139 PERFETTO_LOG("Ftrace start (id=%" PRIu64 ", target_buf=%" PRIu32 ")", id,
140 source_config.target_buffer());
141
Hector Dearmana89cc572018-02-23 12:02:58 +0000142 FtraceConfig proto_config = source_config.ftrace_config();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000143
144 // TODO(hjd): Static cast is bad, target_buffer() should return a BufferID.
145 auto trace_writer = endpoint_->CreateTraceWriter(
146 static_cast<BufferID>(source_config.target_buffer()));
Hector Dearmanc8488032018-03-02 13:12:01 +0000147 auto delegate = std::unique_ptr<SinkDelegate>(
148 new SinkDelegate(task_runner_, std::move(trace_writer)));
Isabelle Taylord404ea12018-02-19 17:28:01 +0000149 auto sink = ftrace_->CreateSink(std::move(proto_config), delegate.get());
Hector Dearmanee3c49d2018-02-28 14:10:22 +0000150 if (!sink) {
151 PERFETTO_ELOG("Failed to start tracing (maybe someone else is using it?)");
152 return;
153 }
Isabelle Taylord404ea12018-02-19 17:28:01 +0000154 delegate->sink(std::move(sink));
155 delegates_.emplace(id, std::move(delegate));
Anna Zappone27ac99c2018-03-06 14:25:35 +0000156 AddWatchdogsTimer(id, source_config);
157}
158
159void ProbesProducer::CreateInodeFileMapDataSourceInstance(
160 DataSourceInstanceID id,
161 const DataSourceConfig& source_config) {
162 PERFETTO_LOG("Inode file map start (id=%" PRIu64 ", target_buf=%" PRIu32 ")",
163 id, source_config.target_buffer());
164 auto trace_writer = endpoint_->CreateTraceWriter(
165 static_cast<BufferID>(source_config.target_buffer()));
166 auto file_map_source = std::unique_ptr<InodeFileMapDataSource>(
167 new InodeFileMapDataSource(std::move(trace_writer)));
168 file_map_sources_.emplace(id, std::move(file_map_source));
169 AddWatchdogsTimer(id, source_config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000170}
171
172void ProbesProducer::CreateProcessStatsDataSourceInstance(
173 const DataSourceConfig& source_config) {
174 auto trace_writer = endpoint_->CreateTraceWriter(
175 static_cast<BufferID>(source_config.target_buffer()));
176 procfs_utils::ProcessMap processes;
177 auto trace_packet = trace_writer->NewTracePacket();
178 protos::pbzero::ProcessTree* process_tree = trace_packet->set_process_tree();
179
180 file_utils::ForEachPidInProcPath(
181 "/proc", [&processes, &process_tree](int pid) {
182 if (!processes.count(pid)) {
183 if (procfs_utils::ReadTgid(pid) != pid)
184 return;
185 processes[pid] = procfs_utils::ReadProcessInfo(pid);
186 }
187 ProcessInfo* process = processes[pid].get();
188 procfs_utils::ReadProcessThreads(process);
189 auto* process_writer = process_tree->add_processes();
190 process_writer->set_pid(process->pid);
191 process_writer->set_ppid(process->ppid);
Isabelle Taylore3504972018-02-26 10:27:51 +0000192 for (const auto& field : process->cmdline)
193 process_writer->add_cmdline(field.c_str());
Isabelle Taylord404ea12018-02-19 17:28:01 +0000194 for (auto& thread : process->threads) {
195 auto* thread_writer = process_writer->add_threads();
196 thread_writer->set_tid(thread.second.tid);
197 thread_writer->set_name(thread.second.name);
198 }
199 });
200 trace_packet->Finalize();
201}
202
203void ProbesProducer::TearDownDataSourceInstance(DataSourceInstanceID id) {
204 PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
205 PERFETTO_DCHECK(instances_.count(id));
206 if (instances_[id] == kFtraceSourceName) {
207 size_t removed = delegates_.erase(id);
208 PERFETTO_DCHECK(removed == 1);
Florian Mayerb8c02162018-02-26 15:52:15 +0000209 // Might return 0 if trace_duration_ms == 0.
210 watchdogs_.erase(id);
Anna Zappone27ac99c2018-03-06 14:25:35 +0000211 } else if (instances_[id] == kInodeFileMapSourceName) {
212 size_t removed = file_map_sources_.erase(id);
213 PERFETTO_DCHECK(removed == 1);
214 watchdogs_.erase(id);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000215 }
216}
217
218void ProbesProducer::ConnectWithRetries(const char* socket_name,
219 base::TaskRunner* task_runner) {
220 PERFETTO_DCHECK(state_ == kNotStarted);
221 state_ = kNotConnected;
222
223 ResetConnectionBackoff();
224 socket_name_ = socket_name;
225 task_runner_ = task_runner;
226 Connect();
227}
228
229void ProbesProducer::Connect() {
230 PERFETTO_DCHECK(state_ == kNotConnected);
231 state_ = kConnecting;
232 endpoint_ = ProducerIPCClient::Connect(socket_name_, this, task_runner_);
233}
234
235void ProbesProducer::IncreaseConnectionBackoff() {
236 connection_backoff_ms_ *= 2;
237 if (connection_backoff_ms_ > kMaxConnectionBackoffMs)
238 connection_backoff_ms_ = kMaxConnectionBackoffMs;
239}
240
241void ProbesProducer::ResetConnectionBackoff() {
242 connection_backoff_ms_ = kInitialConnectionBackoffMs;
243}
244
Hector Dearmanc8488032018-03-02 13:12:01 +0000245ProbesProducer::SinkDelegate::SinkDelegate(base::TaskRunner* task_runner,
246 std::unique_ptr<TraceWriter> writer)
247 : task_runner_(task_runner),
248 writer_(std::move(writer)),
249 weak_factory_(this) {}
Isabelle Taylord404ea12018-02-19 17:28:01 +0000250
251ProbesProducer::SinkDelegate::~SinkDelegate() = default;
252
253ProbesProducer::FtraceBundleHandle
Hector Dearmanc8488032018-03-02 13:12:01 +0000254
Isabelle Taylord404ea12018-02-19 17:28:01 +0000255ProbesProducer::SinkDelegate::GetBundleForCpu(size_t) {
256 trace_packet_ = writer_->NewTracePacket();
257 return FtraceBundleHandle(trace_packet_->set_ftrace_events());
258}
259
Hector Dearmanc8488032018-03-02 13:12:01 +0000260void ProbesProducer::SinkDelegate::OnBundleComplete(
261 size_t,
262 FtraceBundleHandle,
263 const FtraceMetadata& metadata) {
Isabelle Taylord404ea12018-02-19 17:28:01 +0000264 trace_packet_->Finalize();
Hector Dearmanc8488032018-03-02 13:12:01 +0000265 if (!metadata.inodes.empty()) {
266 auto weak_this = weak_factory_.GetWeakPtr();
267 auto inodes = metadata.inodes;
268 task_runner_->PostTask([weak_this, inodes] {
269 if (weak_this)
270 weak_this->OnInodes(inodes);
271 });
272 }
273}
274
275void ProbesProducer::SinkDelegate::OnInodes(
276 const std::vector<uint64_t>& inodes) {
277 PERFETTO_DLOG("Saw FtraceBundle with %zu inodes.", inodes.size());
Isabelle Taylord404ea12018-02-19 17:28:01 +0000278}
279
Anna Zappone27ac99c2018-03-06 14:25:35 +0000280ProbesProducer::InodeFileMapDataSource::InodeFileMapDataSource(
281 std::unique_ptr<TraceWriter> writer)
282 : writer_(std::move(writer)) {}
283
284ProbesProducer::InodeFileMapDataSource::~InodeFileMapDataSource() = default;
285
286void ProbesProducer::InodeFileMapDataSource::WriteInodes(
287 const FtraceMetadata& metadata) {
288 auto trace_packet = writer_->NewTracePacket();
289 auto inode_file_map = trace_packet->set_inode_file_map();
290 // TODO(azappone): Add block_device_id and mount_points
291 auto inodes = metadata.inodes;
292 for (const auto& inode : inodes) {
293 auto* entry = inode_file_map->add_entries();
294 entry->set_inode_number(inode);
295 // TODO(azappone): Add resolving filepaths and type
296 }
297 trace_packet->Finalize();
298}
299
Isabelle Taylord404ea12018-02-19 17:28:01 +0000300} // namespace perfetto