blob: 57789a99a914f6e8cdc0340ddb5ad9c6a467c729 [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>
20#include <string>
21
22#include "perfetto/base/logging.h"
23#include "perfetto/traced/traced.h"
24#include "perfetto/tracing/core/data_source_config.h"
25#include "perfetto/tracing/core/data_source_descriptor.h"
Hector Dearmana89cc572018-02-23 12:02:58 +000026#include "perfetto/tracing/core/ftrace_config.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000027#include "perfetto/tracing/core/trace_config.h"
28#include "perfetto/tracing/core/trace_packet.h"
29
30#include "src/process_stats/file_utils.h"
31#include "src/process_stats/procfs_utils.h"
32
33#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
34#include "perfetto/trace/ps/process_tree.pbzero.h"
35#include "perfetto/trace/trace_packet.pbzero.h"
36
37namespace perfetto {
38namespace {
39
40uint64_t kInitialConnectionBackoffMs = 100;
41uint64_t kMaxConnectionBackoffMs = 30 * 1000;
42const char* kFtraceSourceName = "com.google.perfetto.ftrace";
43const char* kProcessStatsSourceName = "com.google.perfetto.process_stats";
44
45} // namespace.
46
47// State transition diagram:
48// +----------------------------+
49// v +
50// NotStarted -> NotConnected -> Connecting -> Connected
51// ^ +
52// +--------------+
53//
54
55ProbesProducer::~ProbesProducer() = default;
56
57void ProbesProducer::OnConnect() {
58 PERFETTO_DCHECK(state_ == kConnecting);
59 state_ = kConnected;
60 ResetConnectionBackoff();
61 PERFETTO_LOG("Connected to the service");
62
63 DataSourceDescriptor ftrace_descriptor;
64 ftrace_descriptor.set_name(kFtraceSourceName);
65 endpoint_->RegisterDataSource(ftrace_descriptor,
66 [](DataSourceInstanceID id) {});
67
68 DataSourceDescriptor process_stats_descriptor;
69 process_stats_descriptor.set_name(kProcessStatsSourceName);
70 endpoint_->RegisterDataSource(process_stats_descriptor,
71 [](DataSourceInstanceID id) {});
72}
73
74void ProbesProducer::OnDisconnect() {
75 PERFETTO_DCHECK(state_ == kConnected || state_ == kConnecting);
76 state_ = kNotConnected;
77 PERFETTO_LOG("Disconnected from tracing service");
78 IncreaseConnectionBackoff();
79
80 // TODO(hjd): Erase all sinks and add e2e test for this.
81 task_runner_->PostDelayedTask([this] { this->Connect(); },
82 connection_backoff_ms_);
83}
84
85void ProbesProducer::CreateDataSourceInstance(
86 DataSourceInstanceID id,
87 const DataSourceConfig& source_config) {
88 instances_[id] = source_config.name();
Isabelle Taylord404ea12018-02-19 17:28:01 +000089 if (source_config.name() == kFtraceSourceName) {
90 CreateFtraceDataSourceInstance(id, source_config);
91 } else if (source_config.name() == kProcessStatsSourceName) {
92 CreateProcessStatsDataSourceInstance(source_config);
93 } else {
94 PERFETTO_ELOG("Data source name: %s not recognised.",
95 source_config.name().c_str());
96 }
97}
98
99void ProbesProducer::CreateFtraceDataSourceInstance(
100 DataSourceInstanceID id,
101 const DataSourceConfig& source_config) {
102 // Don't retry if FtraceController::Create() failed once.
103 // This can legitimately happen on user builds where we cannot access the
104 // debug paths, e.g., because of SELinux rules.
105 if (ftrace_creation_failed_)
106 return;
107
108 // Lazily create on the first instance.
109 if (!ftrace_) {
110 ftrace_ = FtraceController::Create(task_runner_);
111
112 if (!ftrace_) {
113 PERFETTO_ELOG("Failed to create FtraceController");
114 ftrace_creation_failed_ = true;
115 return;
116 }
117
118 ftrace_->DisableAllEvents();
119 ftrace_->ClearTrace();
120 }
121
122 PERFETTO_LOG("Ftrace start (id=%" PRIu64 ", target_buf=%" PRIu32 ")", id,
123 source_config.target_buffer());
124
Hector Dearmana89cc572018-02-23 12:02:58 +0000125 FtraceConfig proto_config = source_config.ftrace_config();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000126
127 // TODO(hjd): Static cast is bad, target_buffer() should return a BufferID.
128 auto trace_writer = endpoint_->CreateTraceWriter(
129 static_cast<BufferID>(source_config.target_buffer()));
130 auto delegate =
131 std::unique_ptr<SinkDelegate>(new SinkDelegate(std::move(trace_writer)));
132 auto sink = ftrace_->CreateSink(std::move(proto_config), delegate.get());
Hector Dearmanee3c49d2018-02-28 14:10:22 +0000133 if (!sink) {
134 PERFETTO_ELOG("Failed to start tracing (maybe someone else is using it?)");
135 return;
136 }
Isabelle Taylord404ea12018-02-19 17:28:01 +0000137 delegate->sink(std::move(sink));
138 delegates_.emplace(id, std::move(delegate));
Florian Mayerb8c02162018-02-26 15:52:15 +0000139 // Building on Android, watchdogs_.emplace(id, 2* source_config.duration_ms())
140 // does not compile. Presumably, this is due to some detail in its libc++.
Florian Mayer94efaeb2018-02-26 18:02:29 +0000141 // Add constant (5 s, semi arbitrarily) to account for very short trace
142 // durations.
Florian Mayerb8c02162018-02-26 15:52:15 +0000143 if (source_config.trace_duration_ms() != 0)
144 watchdogs_.emplace(
145 std::piecewise_construct, std::forward_as_tuple(id),
Florian Mayer94efaeb2018-02-26 18:02:29 +0000146 std::forward_as_tuple(5000 + 2 * source_config.trace_duration_ms()));
Isabelle Taylord404ea12018-02-19 17:28:01 +0000147}
148
149void ProbesProducer::CreateProcessStatsDataSourceInstance(
150 const DataSourceConfig& source_config) {
151 auto trace_writer = endpoint_->CreateTraceWriter(
152 static_cast<BufferID>(source_config.target_buffer()));
153 procfs_utils::ProcessMap processes;
154 auto trace_packet = trace_writer->NewTracePacket();
155 protos::pbzero::ProcessTree* process_tree = trace_packet->set_process_tree();
156
157 file_utils::ForEachPidInProcPath(
158 "/proc", [&processes, &process_tree](int pid) {
159 if (!processes.count(pid)) {
160 if (procfs_utils::ReadTgid(pid) != pid)
161 return;
162 processes[pid] = procfs_utils::ReadProcessInfo(pid);
163 }
164 ProcessInfo* process = processes[pid].get();
165 procfs_utils::ReadProcessThreads(process);
166 auto* process_writer = process_tree->add_processes();
167 process_writer->set_pid(process->pid);
168 process_writer->set_ppid(process->ppid);
Isabelle Taylore3504972018-02-26 10:27:51 +0000169 for (const auto& field : process->cmdline)
170 process_writer->add_cmdline(field.c_str());
Isabelle Taylord404ea12018-02-19 17:28:01 +0000171 for (auto& thread : process->threads) {
172 auto* thread_writer = process_writer->add_threads();
173 thread_writer->set_tid(thread.second.tid);
174 thread_writer->set_name(thread.second.name);
175 }
176 });
177 trace_packet->Finalize();
178}
179
180void ProbesProducer::TearDownDataSourceInstance(DataSourceInstanceID id) {
181 PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
182 PERFETTO_DCHECK(instances_.count(id));
183 if (instances_[id] == kFtraceSourceName) {
184 size_t removed = delegates_.erase(id);
185 PERFETTO_DCHECK(removed == 1);
Florian Mayerb8c02162018-02-26 15:52:15 +0000186 // Might return 0 if trace_duration_ms == 0.
187 watchdogs_.erase(id);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000188 }
189}
190
191void ProbesProducer::ConnectWithRetries(const char* socket_name,
192 base::TaskRunner* task_runner) {
193 PERFETTO_DCHECK(state_ == kNotStarted);
194 state_ = kNotConnected;
195
196 ResetConnectionBackoff();
197 socket_name_ = socket_name;
198 task_runner_ = task_runner;
199 Connect();
200}
201
202void ProbesProducer::Connect() {
203 PERFETTO_DCHECK(state_ == kNotConnected);
204 state_ = kConnecting;
205 endpoint_ = ProducerIPCClient::Connect(socket_name_, this, task_runner_);
206}
207
208void ProbesProducer::IncreaseConnectionBackoff() {
209 connection_backoff_ms_ *= 2;
210 if (connection_backoff_ms_ > kMaxConnectionBackoffMs)
211 connection_backoff_ms_ = kMaxConnectionBackoffMs;
212}
213
214void ProbesProducer::ResetConnectionBackoff() {
215 connection_backoff_ms_ = kInitialConnectionBackoffMs;
216}
217
218ProbesProducer::SinkDelegate::SinkDelegate(std::unique_ptr<TraceWriter> writer)
219 : writer_(std::move(writer)) {}
220
221ProbesProducer::SinkDelegate::~SinkDelegate() = default;
222
223ProbesProducer::FtraceBundleHandle
224ProbesProducer::SinkDelegate::GetBundleForCpu(size_t) {
225 trace_packet_ = writer_->NewTracePacket();
226 return FtraceBundleHandle(trace_packet_->set_ftrace_events());
227}
228
229void ProbesProducer::SinkDelegate::OnBundleComplete(size_t,
230 FtraceBundleHandle) {
231 trace_packet_->Finalize();
232}
233
234} // namespace perfetto