1 /*
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 INCLUDE_PERFETTO_FTRACE_READER_FTRACE_CONTROLLER_H_
18 #define INCLUDE_PERFETTO_FTRACE_READER_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/ftrace_reader/ftrace_config.h"
37 #include "perfetto/protozero/message_handle.h"
38 #include "perfetto/traced/data_source_types.h"
39 
40 namespace perfetto {
41 
42 namespace protos {
43 namespace pbzero {
44 class FtraceEventBundle;
45 class FtraceStats;
46 class FtraceCpuStats;
47 }  // namespace pbzero
48 }  // namespace protos
49 
50 using BlockDeviceID = decltype(stat::st_dev);
51 using Inode = decltype(stat::st_ino);
52 
53 struct 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 
67 struct FtraceStats {
68   std::vector<FtraceCpuStats> cpu_stats;
69 
70   void Write(protos::pbzero::FtraceStats*) const;
71 };
72 
73 struct 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 
95 constexpr size_t kMaxSinks = 32;
96 constexpr size_t kMaxCpus = 64;
97 
98 // Method of last resort to reset ftrace state.
99 void HardResetFtraceState();
100 
101 class CpuReader;
102 class EventFilter;
103 class FtraceController;
104 class FtraceConfigMuxer;
105 class FtraceProcfs;
106 class 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.
112 class FtraceSink {
113  public:
114   using FtraceEventBundle = protos::pbzero::FtraceEventBundle;
115   class Delegate {
116    public:
OnCreate(FtraceSink *)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 
config()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 
event_filter()143   EventFilter* event_filter() { return filter_.get(); }
metadata_mutable()144   FtraceMetadata* metadata_mutable() { return &metadata_; }
145 
GetBundleForCpu(size_t cpu)146   protozero::MessageHandle<FtraceEventBundle> GetBundleForCpu(size_t cpu) {
147     return delegate_->GetBundleForCpu(cpu);
148   }
OnBundleComplete(size_t cpu,protozero::MessageHandle<FtraceEventBundle> bundle)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.
166 class 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  // INCLUDE_PERFETTO_FTRACE_READER_FTRACE_CONTROLLER_H_
242