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