Primiano Tucci | de82dae | 2018-06-04 16:17:49 +0200 | [diff] [blame^] | 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 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 | |
| 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: |
| 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. |
| 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 // SRC_TRACED_PROBES_FTRACE_FTRACE_CONTROLLER_H_ |