blob: 381ec83a86f9a62f82a5493c8c8c083c5abb10bf [file] [log] [blame]
Primiano Tuccide82dae2018-06-04 16:17:49 +02001/*
2 * Copyright (C) 2017 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#ifndef SRC_TRACED_PROBES_FTRACE_FTRACE_CONTROLLER_H_
18#define SRC_TRACED_PROBES_FTRACE_FTRACE_CONTROLLER_H_
19
20#include <unistd.h>
21
22#include <sys/stat.h>
23#include <bitset>
24#include <condition_variable>
25#include <map>
26#include <memory>
27#include <mutex>
28#include <set>
29#include <string>
30#include <vector>
31
32#include "gtest/gtest_prod.h"
33#include "perfetto/base/scoped_file.h"
34#include "perfetto/base/task_runner.h"
35#include "perfetto/base/weak_ptr.h"
36#include "perfetto/protozero/message_handle.h"
37#include "perfetto/traced/data_source_types.h"
38#include "src/traced/probes/ftrace/ftrace_config.h"
39
40namespace perfetto {
41
42namespace protos {
43namespace pbzero {
44class FtraceEventBundle;
45class FtraceStats;
46class FtraceCpuStats;
47} // namespace pbzero
48} // namespace protos
49
50using BlockDeviceID = decltype(stat::st_dev);
51using Inode = decltype(stat::st_ino);
52
53struct FtraceCpuStats {
54 uint64_t cpu;
55 uint64_t entries;
56 uint64_t overrun;
57 uint64_t commit_overrun;
58 uint64_t bytes_read;
59 double oldest_event_ts;
60 double now_ts;
61 uint64_t dropped_events;
62 uint64_t read_events;
63
64 void Write(protos::pbzero::FtraceCpuStats*) const;
65};
66
67struct FtraceStats {
68 std::vector<FtraceCpuStats> cpu_stats;
69
70 void Write(protos::pbzero::FtraceStats*) const;
71};
72
73struct FtraceMetadata {
74 FtraceMetadata();
75
76 uint32_t overwrite_count;
77 BlockDeviceID last_seen_device_id = 0;
78#if PERFETTO_DCHECK_IS_ON()
79 bool seen_device_id = false;
80#endif
81 int32_t last_seen_common_pid = 0;
82
83 // A vector not a set to keep the writer_fast.
84 std::vector<std::pair<Inode, BlockDeviceID>> inode_and_device;
85 std::vector<int32_t> pids;
86
87 void AddDevice(BlockDeviceID);
88 void AddInode(Inode);
89 void AddPid(int32_t);
90 void AddCommonPid(int32_t);
91 void Clear();
92 void FinishEvent();
93};
94
95constexpr size_t kMaxSinks = 32;
96constexpr size_t kMaxCpus = 64;
97
98// Method of last resort to reset ftrace state.
99void HardResetFtraceState();
100
101class CpuReader;
102class EventFilter;
103class FtraceController;
104class FtraceConfigMuxer;
105class FtraceProcfs;
106class ProtoTranslationTable;
107
108// To consume ftrace data clients implement a |FtraceSink::Delegate| and use it
109// to create a |FtraceSink|. While the FtraceSink lives FtraceController will
110// call |GetBundleForCpu|, write data into the bundle then call
111// |OnBundleComplete| allowing the client to perform finalization.
112class FtraceSink {
113 public:
114 using FtraceEventBundle = protos::pbzero::FtraceEventBundle;
115 class Delegate {
116 public:
117 virtual void OnCreate(FtraceSink*) {}
118 virtual protozero::MessageHandle<FtraceEventBundle> GetBundleForCpu(
119 size_t) = 0;
120 virtual void OnBundleComplete(size_t,
121 protozero::MessageHandle<FtraceEventBundle>,
122 const FtraceMetadata&) = 0;
123 virtual ~Delegate();
124 };
125
126 FtraceSink(base::WeakPtr<FtraceController>,
127 FtraceConfigId id,
128 FtraceConfig config,
129 std::unique_ptr<EventFilter>,
130 Delegate*);
131 ~FtraceSink();
132
133 void DumpFtraceStats(FtraceStats*);
134
135 const FtraceConfig& config() const { return config_; }
136
137 private:
138 friend FtraceController;
139
140 FtraceSink(const FtraceSink&) = delete;
141 FtraceSink& operator=(const FtraceSink&) = delete;
142
143 EventFilter* event_filter() { return filter_.get(); }
144 FtraceMetadata* metadata_mutable() { return &metadata_; }
145
146 protozero::MessageHandle<FtraceEventBundle> GetBundleForCpu(size_t cpu) {
147 return delegate_->GetBundleForCpu(cpu);
148 }
149 void OnBundleComplete(size_t cpu,
150 protozero::MessageHandle<FtraceEventBundle> bundle) {
151 delegate_->OnBundleComplete(cpu, std::move(bundle), metadata_);
152 metadata_.Clear();
153 }
154
155 const std::set<std::string>& enabled_events();
156
157 base::WeakPtr<FtraceController> controller_weak_;
158 const FtraceConfigId id_;
159 const FtraceConfig config_;
160 std::unique_ptr<EventFilter> filter_;
161 FtraceMetadata metadata_;
162 FtraceSink::Delegate* delegate_;
163};
164
165// Utility class for controlling ftrace.
166class FtraceController {
167 public:
168 static std::unique_ptr<FtraceController> Create(base::TaskRunner*);
169 virtual ~FtraceController();
170
171 std::unique_ptr<FtraceSink> CreateSink(FtraceConfig, FtraceSink::Delegate*);
172
173 void DisableAllEvents();
174 void WriteTraceMarker(const std::string& s);
175 void ClearTrace();
176
177 protected:
178 // Protected for testing.
179 FtraceController(std::unique_ptr<FtraceProcfs>,
180 std::unique_ptr<ProtoTranslationTable>,
181 std::unique_ptr<FtraceConfigMuxer>,
182 base::TaskRunner*);
183
184 // Write
185 void DumpFtraceStats(FtraceStats*);
186
187 // Called to read data from the staging pipe for the given |cpu| and parse it
188 // into the sinks. Protected and virtual for testing.
189 virtual void OnRawFtraceDataAvailable(size_t cpu);
190
191 // Protected and virtual for testing.
192 virtual uint64_t NowMs() const;
193
194 private:
195 friend FtraceSink;
196 friend class TestFtraceController;
197 FRIEND_TEST(FtraceControllerIntegrationTest, EnableDisableEvent);
198
199 FtraceController(const FtraceController&) = delete;
200 FtraceController& operator=(const FtraceController&) = delete;
201
202 // Called on a worker thread when |cpu| has at least one page of data
203 // available for reading.
204 void OnDataAvailable(base::WeakPtr<FtraceController>,
205 size_t generation,
206 size_t cpu,
207 uint32_t drain_period_ms);
208
209 static void DrainCPUs(base::WeakPtr<FtraceController>, size_t generation);
210 static void UnblockReaders(const base::WeakPtr<FtraceController>&);
211
212 uint32_t GetDrainPeriodMs();
213
214 void Register(FtraceSink*);
215 void Unregister(FtraceSink*);
216
217 void StartIfNeeded();
218 void StopIfNeeded();
219
220 // Begin lock-protected members.
221 std::mutex lock_;
222 std::condition_variable data_drained_;
223 std::bitset<kMaxCpus> cpus_to_drain_;
224 bool listening_for_raw_trace_data_ = false;
225 // End lock-protected members.
226
227 std::unique_ptr<FtraceProcfs> ftrace_procfs_;
228 std::unique_ptr<ProtoTranslationTable> table_;
229 std::unique_ptr<FtraceConfigMuxer> ftrace_config_muxer_;
230 size_t generation_ = 0;
231 bool atrace_running_ = false;
232 base::TaskRunner* task_runner_ = nullptr;
233 std::map<size_t, std::unique_ptr<CpuReader>> readers_;
234 std::set<FtraceSink*> sinks_;
235 base::WeakPtrFactory<FtraceController> weak_factory_;
236 PERFETTO_THREAD_CHECKER(thread_checker_)
237};
238
239} // namespace perfetto
240
241#endif // SRC_TRACED_PROBES_FTRACE_FTRACE_CONTROLLER_H_