blob: d3a96b999d56bca13eb3feacc107d39b3b2b8233 [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"
26#include "perfetto/tracing/core/trace_config.h"
27#include "perfetto/tracing/core/trace_packet.h"
28
29#include "src/process_stats/file_utils.h"
30#include "src/process_stats/procfs_utils.h"
31
32#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
33#include "perfetto/trace/ps/process_tree.pbzero.h"
34#include "perfetto/trace/trace_packet.pbzero.h"
35
36namespace perfetto {
37namespace {
38
39uint64_t kInitialConnectionBackoffMs = 100;
40uint64_t kMaxConnectionBackoffMs = 30 * 1000;
41const char* kFtraceSourceName = "com.google.perfetto.ftrace";
42const char* kProcessStatsSourceName = "com.google.perfetto.process_stats";
43
44} // namespace.
45
46// State transition diagram:
47// +----------------------------+
48// v +
49// NotStarted -> NotConnected -> Connecting -> Connected
50// ^ +
51// +--------------+
52//
53
54ProbesProducer::~ProbesProducer() = default;
55
56void ProbesProducer::OnConnect() {
57 PERFETTO_DCHECK(state_ == kConnecting);
58 state_ = kConnected;
59 ResetConnectionBackoff();
60 PERFETTO_LOG("Connected to the service");
61
62 DataSourceDescriptor ftrace_descriptor;
63 ftrace_descriptor.set_name(kFtraceSourceName);
64 endpoint_->RegisterDataSource(ftrace_descriptor,
65 [](DataSourceInstanceID id) {});
66
67 DataSourceDescriptor process_stats_descriptor;
68 process_stats_descriptor.set_name(kProcessStatsSourceName);
69 endpoint_->RegisterDataSource(process_stats_descriptor,
70 [](DataSourceInstanceID id) {});
71}
72
73void ProbesProducer::OnDisconnect() {
74 PERFETTO_DCHECK(state_ == kConnected || state_ == kConnecting);
75 state_ = kNotConnected;
76 PERFETTO_LOG("Disconnected from tracing service");
77 IncreaseConnectionBackoff();
78
79 // TODO(hjd): Erase all sinks and add e2e test for this.
80 task_runner_->PostDelayedTask([this] { this->Connect(); },
81 connection_backoff_ms_);
82}
83
84void ProbesProducer::CreateDataSourceInstance(
85 DataSourceInstanceID id,
86 const DataSourceConfig& source_config) {
87 instances_[id] = source_config.name();
88 // PERFETTO_LOG("DataSourceInstanceID: %llu", id);
89 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
125 // TODO(hjd): Would be nice if ftrace_reader could use the generated config.
126 DataSourceConfig::FtraceConfig proto_config = source_config.ftrace_config();
127
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