blob: 7c81c1dd0c09bc135d698ef2c4eb115d07addffe [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();
89 // PERFETTO_LOG("DataSourceInstanceID: %llu", id);
90 if (source_config.name() == kFtraceSourceName) {
91 CreateFtraceDataSourceInstance(id, source_config);
92 } else if (source_config.name() == kProcessStatsSourceName) {
93 CreateProcessStatsDataSourceInstance(source_config);
94 } else {
95 PERFETTO_ELOG("Data source name: %s not recognised.",
96 source_config.name().c_str());
97 }
98}
99
100void ProbesProducer::CreateFtraceDataSourceInstance(
101 DataSourceInstanceID id,
102 const DataSourceConfig& source_config) {
103 // Don't retry if FtraceController::Create() failed once.
104 // This can legitimately happen on user builds where we cannot access the
105 // debug paths, e.g., because of SELinux rules.
106 if (ftrace_creation_failed_)
107 return;
108
109 // Lazily create on the first instance.
110 if (!ftrace_) {
111 ftrace_ = FtraceController::Create(task_runner_);
112
113 if (!ftrace_) {
114 PERFETTO_ELOG("Failed to create FtraceController");
115 ftrace_creation_failed_ = true;
116 return;
117 }
118
119 ftrace_->DisableAllEvents();
120 ftrace_->ClearTrace();
121 }
122
123 PERFETTO_LOG("Ftrace start (id=%" PRIu64 ", target_buf=%" PRIu32 ")", id,
124 source_config.target_buffer());
125
Hector Dearmana89cc572018-02-23 12:02:58 +0000126 FtraceConfig proto_config = source_config.ftrace_config();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000127
128 // TODO(hjd): Static cast is bad, target_buffer() should return a BufferID.
129 auto trace_writer = endpoint_->CreateTraceWriter(
130 static_cast<BufferID>(source_config.target_buffer()));
131 auto delegate =
132 std::unique_ptr<SinkDelegate>(new SinkDelegate(std::move(trace_writer)));
133 auto sink = ftrace_->CreateSink(std::move(proto_config), delegate.get());
134 PERFETTO_CHECK(sink);
135 delegate->sink(std::move(sink));
136 delegates_.emplace(id, std::move(delegate));
137}
138
139void ProbesProducer::CreateProcessStatsDataSourceInstance(
140 const DataSourceConfig& source_config) {
141 auto trace_writer = endpoint_->CreateTraceWriter(
142 static_cast<BufferID>(source_config.target_buffer()));
143 procfs_utils::ProcessMap processes;
144 auto trace_packet = trace_writer->NewTracePacket();
145 protos::pbzero::ProcessTree* process_tree = trace_packet->set_process_tree();
146
147 file_utils::ForEachPidInProcPath(
148 "/proc", [&processes, &process_tree](int pid) {
149 if (!processes.count(pid)) {
150 if (procfs_utils::ReadTgid(pid) != pid)
151 return;
152 processes[pid] = procfs_utils::ReadProcessInfo(pid);
153 }
154 ProcessInfo* process = processes[pid].get();
155 procfs_utils::ReadProcessThreads(process);
156 auto* process_writer = process_tree->add_processes();
157 process_writer->set_pid(process->pid);
158 process_writer->set_ppid(process->ppid);
159 process_writer->add_cmdline(process->cmdline);
160
161 for (auto& thread : process->threads) {
162 auto* thread_writer = process_writer->add_threads();
163 thread_writer->set_tid(thread.second.tid);
164 thread_writer->set_name(thread.second.name);
165 }
166 });
167 trace_packet->Finalize();
168}
169
170void ProbesProducer::TearDownDataSourceInstance(DataSourceInstanceID id) {
171 PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
172 PERFETTO_DCHECK(instances_.count(id));
173 if (instances_[id] == kFtraceSourceName) {
174 size_t removed = delegates_.erase(id);
175 PERFETTO_DCHECK(removed == 1);
176 }
177}
178
179void ProbesProducer::ConnectWithRetries(const char* socket_name,
180 base::TaskRunner* task_runner) {
181 PERFETTO_DCHECK(state_ == kNotStarted);
182 state_ = kNotConnected;
183
184 ResetConnectionBackoff();
185 socket_name_ = socket_name;
186 task_runner_ = task_runner;
187 Connect();
188}
189
190void ProbesProducer::Connect() {
191 PERFETTO_DCHECK(state_ == kNotConnected);
192 state_ = kConnecting;
193 endpoint_ = ProducerIPCClient::Connect(socket_name_, this, task_runner_);
194}
195
196void ProbesProducer::IncreaseConnectionBackoff() {
197 connection_backoff_ms_ *= 2;
198 if (connection_backoff_ms_ > kMaxConnectionBackoffMs)
199 connection_backoff_ms_ = kMaxConnectionBackoffMs;
200}
201
202void ProbesProducer::ResetConnectionBackoff() {
203 connection_backoff_ms_ = kInitialConnectionBackoffMs;
204}
205
206ProbesProducer::SinkDelegate::SinkDelegate(std::unique_ptr<TraceWriter> writer)
207 : writer_(std::move(writer)) {}
208
209ProbesProducer::SinkDelegate::~SinkDelegate() = default;
210
211ProbesProducer::FtraceBundleHandle
212ProbesProducer::SinkDelegate::GetBundleForCpu(size_t) {
213 trace_packet_ = writer_->NewTracePacket();
214 return FtraceBundleHandle(trace_packet_->set_ftrace_events());
215}
216
217void ProbesProducer::SinkDelegate::OnBundleComplete(size_t,
218 FtraceBundleHandle) {
219 trace_packet_->Finalize();
220}
221
222} // namespace perfetto