blob: a18181dd2de77f59284b868360b2510531eabddb [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 Zappone4ea73c02018-03-09 16:01:21 +000020#include <sys/stat.h>
Anna Zappone27ac99c2018-03-06 14:25:35 +000021#include <queue>
Isabelle Taylord404ea12018-02-19 17:28:01 +000022#include <string>
23
24#include "perfetto/base/logging.h"
Hector Dearman0ff07c72018-03-15 09:54:46 +000025#include "perfetto/base/weak_ptr.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000026#include "perfetto/traced/traced.h"
27#include "perfetto/tracing/core/data_source_config.h"
28#include "perfetto/tracing/core/data_source_descriptor.h"
Hector Dearmana89cc572018-02-23 12:02:58 +000029#include "perfetto/tracing/core/ftrace_config.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000030#include "perfetto/tracing/core/trace_config.h"
31#include "perfetto/tracing/core/trace_packet.h"
Anna Zappone2a6f9042018-03-14 13:26:07 +000032#include "src/traced/probes/filesystem/inode_file_data_source.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000033
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"
Isabelle Taylord404ea12018-02-19 17:28:01 +000036#include "perfetto/trace/trace_packet.pbzero.h"
37
38namespace perfetto {
39namespace {
40
41uint64_t kInitialConnectionBackoffMs = 100;
42uint64_t kMaxConnectionBackoffMs = 30 * 1000;
Primiano Tucci578d7842018-03-29 15:27:05 +010043constexpr char kFtraceSourceName[] = "linux.ftrace";
44constexpr char kProcessStatsSourceName[] = "linux.process_stats";
45constexpr char kInodeMapSourceName[] = "linux.inode_file_map";
Isabelle Taylord404ea12018-02-19 17:28:01 +000046
47} // namespace.
48
49// State transition diagram:
50// +----------------------------+
51// v +
52// NotStarted -> NotConnected -> Connecting -> Connected
53// ^ +
54// +--------------+
55//
56
Hector Dearmanc8488032018-03-02 13:12:01 +000057ProbesProducer::ProbesProducer() {}
Isabelle Taylord404ea12018-02-19 17:28:01 +000058ProbesProducer::~ProbesProducer() = default;
59
60void ProbesProducer::OnConnect() {
61 PERFETTO_DCHECK(state_ == kConnecting);
62 state_ = kConnected;
63 ResetConnectionBackoff();
64 PERFETTO_LOG("Connected to the service");
65
66 DataSourceDescriptor ftrace_descriptor;
67 ftrace_descriptor.set_name(kFtraceSourceName);
Primiano Tucci9daa4832018-03-28 23:28:17 +010068 endpoint_->RegisterDataSource(ftrace_descriptor);
Isabelle Taylord404ea12018-02-19 17:28:01 +000069
70 DataSourceDescriptor process_stats_descriptor;
71 process_stats_descriptor.set_name(kProcessStatsSourceName);
Primiano Tucci9daa4832018-03-28 23:28:17 +010072 endpoint_->RegisterDataSource(process_stats_descriptor);
Anna Zappone27ac99c2018-03-06 14:25:35 +000073
74 DataSourceDescriptor inode_map_descriptor;
Hector Dearman0ff07c72018-03-15 09:54:46 +000075 inode_map_descriptor.set_name(kInodeMapSourceName);
Primiano Tucci9daa4832018-03-28 23:28:17 +010076 endpoint_->RegisterDataSource(inode_map_descriptor);
Isabelle Taylord404ea12018-02-19 17:28:01 +000077}
78
79void ProbesProducer::OnDisconnect() {
80 PERFETTO_DCHECK(state_ == kConnected || state_ == kConnecting);
81 state_ = kNotConnected;
82 PERFETTO_LOG("Disconnected from tracing service");
83 IncreaseConnectionBackoff();
84
85 // TODO(hjd): Erase all sinks and add e2e test for this.
86 task_runner_->PostDelayedTask([this] { this->Connect(); },
87 connection_backoff_ms_);
88}
89
Hector Dearman0ff07c72018-03-15 09:54:46 +000090void ProbesProducer::CreateDataSourceInstance(DataSourceInstanceID instance_id,
91 const DataSourceConfig& config) {
92 // TODO(hjd): This a hack since we don't actually know the session id. For
93 // now we'll assume anything wit hthe same target buffer is in the same
94 // session.
95 TracingSessionID session_id = config.target_buffer();
96
97 if (config.name() == kFtraceSourceName) {
Hector Dearmanbcb56fb2018-03-26 13:59:24 +010098 if (!CreateFtraceDataSourceInstance(session_id, instance_id, config))
99 failed_sources_.insert(instance_id);
Hector Dearman0ff07c72018-03-15 09:54:46 +0000100 } else if (config.name() == kInodeMapSourceName) {
101 CreateInodeFileDataSourceInstance(session_id, instance_id, config);
102 } else if (config.name() == kProcessStatsSourceName) {
103 CreateProcessStatsDataSourceInstance(session_id, instance_id, config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000104 } else {
105 PERFETTO_ELOG("Data source name: %s not recognised.",
Hector Dearman0ff07c72018-03-15 09:54:46 +0000106 config.name().c_str());
107 return;
108 }
109
110 std::map<TracingSessionID, InodeFileDataSource*> file_sources;
111 std::map<TracingSessionID, ProcessStatsDataSource*> ps_sources;
112 for (const auto& pair : file_map_sources_)
113 file_sources[pair.second->session_id()] = pair.second.get();
114 for (const auto& pair : process_stats_sources_)
115 ps_sources[pair.second->session_id()] = pair.second.get();
116
117 for (const auto& id_to_source : delegates_) {
118 const std::unique_ptr<SinkDelegate>& source = id_to_source.second;
119 if (session_id != source->session_id())
120 continue;
121 if (!source->ps_source() && ps_sources.count(session_id))
122 source->set_ps_source(ps_sources[session_id]->GetWeakPtr());
123 if (!source->file_source() && file_sources.count(session_id))
124 source->set_file_source(file_sources[session_id]->GetWeakPtr());
Isabelle Taylord404ea12018-02-19 17:28:01 +0000125 }
126}
127
Anna Zappone27ac99c2018-03-06 14:25:35 +0000128void ProbesProducer::AddWatchdogsTimer(DataSourceInstanceID id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000129 const DataSourceConfig& config) {
130 if (config.trace_duration_ms() != 0)
Anna Zappone27ac99c2018-03-06 14:25:35 +0000131 watchdogs_.emplace(id, base::Watchdog::GetInstance()->CreateFatalTimer(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000132 5000 + 2 * config.trace_duration_ms()));
Anna Zappone27ac99c2018-03-06 14:25:35 +0000133}
134
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100135bool ProbesProducer::CreateFtraceDataSourceInstance(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000136 TracingSessionID session_id,
Isabelle Taylord404ea12018-02-19 17:28:01 +0000137 DataSourceInstanceID id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000138 const DataSourceConfig& config) {
Isabelle Taylord404ea12018-02-19 17:28:01 +0000139 // Don't retry if FtraceController::Create() failed once.
140 // This can legitimately happen on user builds where we cannot access the
141 // debug paths, e.g., because of SELinux rules.
142 if (ftrace_creation_failed_)
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100143 return false;
Isabelle Taylord404ea12018-02-19 17:28:01 +0000144
145 // Lazily create on the first instance.
146 if (!ftrace_) {
147 ftrace_ = FtraceController::Create(task_runner_);
148
149 if (!ftrace_) {
150 PERFETTO_ELOG("Failed to create FtraceController");
151 ftrace_creation_failed_ = true;
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100152 return false;
Isabelle Taylord404ea12018-02-19 17:28:01 +0000153 }
154
155 ftrace_->DisableAllEvents();
156 ftrace_->ClearTrace();
157 }
158
159 PERFETTO_LOG("Ftrace start (id=%" PRIu64 ", target_buf=%" PRIu32 ")", id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000160 config.target_buffer());
Isabelle Taylord404ea12018-02-19 17:28:01 +0000161
Hector Dearman0ff07c72018-03-15 09:54:46 +0000162 FtraceConfig proto_config = config.ftrace_config();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000163
164 // TODO(hjd): Static cast is bad, target_buffer() should return a BufferID.
165 auto trace_writer = endpoint_->CreateTraceWriter(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000166 static_cast<BufferID>(config.target_buffer()));
Hector Dearmanc8488032018-03-02 13:12:01 +0000167 auto delegate = std::unique_ptr<SinkDelegate>(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000168 new SinkDelegate(session_id, task_runner_, std::move(trace_writer)));
Isabelle Taylord404ea12018-02-19 17:28:01 +0000169 auto sink = ftrace_->CreateSink(std::move(proto_config), delegate.get());
Hector Dearmanee3c49d2018-02-28 14:10:22 +0000170 if (!sink) {
171 PERFETTO_ELOG("Failed to start tracing (maybe someone else is using it?)");
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100172 return false;
Hector Dearmanee3c49d2018-02-28 14:10:22 +0000173 }
Hector Dearman210dc6f2018-03-12 10:51:07 +0000174 delegate->set_sink(std::move(sink));
Isabelle Taylord404ea12018-02-19 17:28:01 +0000175 delegates_.emplace(id, std::move(delegate));
Hector Dearman0ff07c72018-03-15 09:54:46 +0000176 AddWatchdogsTimer(id, config);
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100177 return true;
Anna Zappone27ac99c2018-03-06 14:25:35 +0000178}
179
Anna Zappone2a6f9042018-03-14 13:26:07 +0000180void ProbesProducer::CreateInodeFileDataSourceInstance(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000181 TracingSessionID session_id,
Anna Zappone27ac99c2018-03-06 14:25:35 +0000182 DataSourceInstanceID id,
183 const DataSourceConfig& source_config) {
184 PERFETTO_LOG("Inode file map start (id=%" PRIu64 ", target_buf=%" PRIu32 ")",
185 id, source_config.target_buffer());
186 auto trace_writer = endpoint_->CreateTraceWriter(
187 static_cast<BufferID>(source_config.target_buffer()));
Anna Zappone2a6f9042018-03-14 13:26:07 +0000188 if (system_inodes_.empty())
Hector Dearman7fabd702018-03-28 12:37:15 +0100189 CreateStaticDeviceToInodeMap("/system", &system_inodes_);
Florian Mayer112376e2018-03-28 16:20:41 +0100190 auto file_map_source = std::unique_ptr<InodeFileDataSource>(
191 new InodeFileDataSource(task_runner_, session_id, &system_inodes_,
192 &cache_, std::move(trace_writer)));
Anna Zappone27ac99c2018-03-06 14:25:35 +0000193 file_map_sources_.emplace(id, std::move(file_map_source));
194 AddWatchdogsTimer(id, source_config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000195}
196
197void ProbesProducer::CreateProcessStatsDataSourceInstance(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000198 TracingSessionID session_id,
Hector Dearman77451692018-03-08 16:21:13 +0000199 DataSourceInstanceID id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000200 const DataSourceConfig& config) {
Hector Dearman77451692018-03-08 16:21:13 +0000201 PERFETTO_DCHECK(process_stats_sources_.count(id) == 0);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000202 auto trace_writer = endpoint_->CreateTraceWriter(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000203 static_cast<BufferID>(config.target_buffer()));
Hector Dearmanebf07c72018-03-13 10:31:05 +0000204 auto source = std::unique_ptr<ProcessStatsDataSource>(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000205 new ProcessStatsDataSource(session_id, std::move(trace_writer)));
Hector Dearmanebf07c72018-03-13 10:31:05 +0000206 auto it_and_inserted = process_stats_sources_.emplace(id, std::move(source));
207 PERFETTO_DCHECK(it_and_inserted.second);
208 it_and_inserted.first->second->WriteAllProcesses();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000209}
210
211void ProbesProducer::TearDownDataSourceInstance(DataSourceInstanceID id) {
212 PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
Hector Dearman77451692018-03-08 16:21:13 +0000213 // |id| could be the id of any of the datasources we handle:
Hector Dearmanaa69aff2018-03-26 19:49:23 +0100214 PERFETTO_DCHECK((failed_sources_.count(id) + delegates_.count(id) +
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100215 process_stats_sources_.count(id) +
Hector Dearman77451692018-03-08 16:21:13 +0000216 file_map_sources_.count(id)) == 1);
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100217 failed_sources_.erase(id);
Hector Dearman77451692018-03-08 16:21:13 +0000218 delegates_.erase(id);
219 process_stats_sources_.erase(id);
220 file_map_sources_.erase(id);
221 watchdogs_.erase(id);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000222}
223
Isabelle Taylor69faa902018-03-21 15:42:03 +0000224void ProbesProducer::OnTracingStart() {}
225void ProbesProducer::OnTracingStop() {}
226
Isabelle Taylord404ea12018-02-19 17:28:01 +0000227void ProbesProducer::ConnectWithRetries(const char* socket_name,
228 base::TaskRunner* task_runner) {
229 PERFETTO_DCHECK(state_ == kNotStarted);
230 state_ = kNotConnected;
231
232 ResetConnectionBackoff();
233 socket_name_ = socket_name;
234 task_runner_ = task_runner;
235 Connect();
236}
237
238void ProbesProducer::Connect() {
239 PERFETTO_DCHECK(state_ == kNotConnected);
240 state_ = kConnecting;
Isabelle Taylor86262cb2018-03-27 16:00:54 +0100241 endpoint_ = ProducerIPCClient::Connect(
Primiano Tucci578d7842018-03-29 15:27:05 +0100242 socket_name_, this, "perfetto.traced_probes", task_runner_);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000243}
244
245void ProbesProducer::IncreaseConnectionBackoff() {
246 connection_backoff_ms_ *= 2;
247 if (connection_backoff_ms_ > kMaxConnectionBackoffMs)
248 connection_backoff_ms_ = kMaxConnectionBackoffMs;
249}
250
251void ProbesProducer::ResetConnectionBackoff() {
252 connection_backoff_ms_ = kInitialConnectionBackoffMs;
253}
254
Hector Dearman0ff07c72018-03-15 09:54:46 +0000255ProbesProducer::SinkDelegate::SinkDelegate(TracingSessionID id,
256 base::TaskRunner* task_runner,
Hector Dearmanc8488032018-03-02 13:12:01 +0000257 std::unique_ptr<TraceWriter> writer)
Hector Dearman0ff07c72018-03-15 09:54:46 +0000258 : session_id_(id),
259 task_runner_(task_runner),
Hector Dearmanc8488032018-03-02 13:12:01 +0000260 writer_(std::move(writer)),
261 weak_factory_(this) {}
Isabelle Taylord404ea12018-02-19 17:28:01 +0000262
263ProbesProducer::SinkDelegate::~SinkDelegate() = default;
264
265ProbesProducer::FtraceBundleHandle
266ProbesProducer::SinkDelegate::GetBundleForCpu(size_t) {
267 trace_packet_ = writer_->NewTracePacket();
268 return FtraceBundleHandle(trace_packet_->set_ftrace_events());
269}
270
Hector Dearmanc8488032018-03-02 13:12:01 +0000271void ProbesProducer::SinkDelegate::OnBundleComplete(
272 size_t,
273 FtraceBundleHandle,
274 const FtraceMetadata& metadata) {
Isabelle Taylord404ea12018-02-19 17:28:01 +0000275 trace_packet_->Finalize();
Hector Dearman0ff07c72018-03-15 09:54:46 +0000276
Hector Dearman3c4e5c22018-03-29 11:31:55 +0100277 if (ps_source_ && !metadata.pids.empty()) {
278 const auto& pids = metadata.pids;
279 auto weak_ps_source = ps_source_;
280 task_runner_->PostTask([weak_ps_source, pids] {
281 if (weak_ps_source)
282 weak_ps_source->OnPids(pids);
283 });
284 }
285
Anna Zappone8ce30872018-03-19 17:01:15 +0000286 if (file_source_ && !metadata.inode_and_device.empty()) {
287 auto inodes = metadata.inode_and_device;
Hector Dearman0ff07c72018-03-15 09:54:46 +0000288 auto weak_file_source = file_source_;
289 task_runner_->PostTask([weak_file_source, inodes] {
290 if (weak_file_source)
291 weak_file_source->OnInodes(inodes);
Hector Dearmanc8488032018-03-02 13:12:01 +0000292 });
293 }
294}
295
Isabelle Taylord404ea12018-02-19 17:28:01 +0000296} // namespace perfetto