1 /* 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 #ifndef SRC_TRACED_PROBES_FTRACE_FTRACE_CONFIG_MUXER_H_ 18 #define SRC_TRACED_PROBES_FTRACE_FTRACE_CONFIG_MUXER_H_ 19 20 #include <map> 21 #include <optional> 22 #include <set> 23 24 #include "src/kernel_utils/syscall_table.h" 25 #include "src/traced/probes/ftrace/atrace_wrapper.h" 26 #include "src/traced/probes/ftrace/compact_sched.h" 27 #include "src/traced/probes/ftrace/ftrace_config_utils.h" 28 #include "src/traced/probes/ftrace/ftrace_print_filter.h" 29 #include "src/traced/probes/ftrace/ftrace_procfs.h" 30 #include "src/traced/probes/ftrace/proto_translation_table.h" 31 32 namespace perfetto { 33 34 namespace protos { 35 namespace pbzero { 36 enum FtraceClock : int32_t; 37 } // namespace pbzero 38 } // namespace protos 39 40 struct FtraceSetupErrors; 41 42 // State held by the muxer per data source, used to parse ftrace according to 43 // that data source's config. 44 struct FtraceDataSourceConfig { FtraceDataSourceConfigFtraceDataSourceConfig45 FtraceDataSourceConfig(EventFilter event_filter_in, 46 EventFilter syscall_filter_in, 47 CompactSchedConfig compact_sched_in, 48 std::optional<FtracePrintFilterConfig> print_filter_in, 49 std::vector<std::string> atrace_apps_in, 50 std::vector<std::string> atrace_categories_in, 51 bool symbolize_ksyms_in, 52 uint32_t buffer_percent_in, 53 base::FlatSet<int64_t> syscalls_returning_fd_in) 54 : event_filter(std::move(event_filter_in)), 55 syscall_filter(std::move(syscall_filter_in)), 56 compact_sched(compact_sched_in), 57 print_filter(std::move(print_filter_in)), 58 atrace_apps(std::move(atrace_apps_in)), 59 atrace_categories(std::move(atrace_categories_in)), 60 symbolize_ksyms(symbolize_ksyms_in), 61 buffer_percent(buffer_percent_in), 62 syscalls_returning_fd(std::move(syscalls_returning_fd_in)) {} 63 // The event filter allows to quickly check if a certain ftrace event with id 64 // x is enabled for this data source. 65 EventFilter event_filter; 66 67 // Specifies the syscalls (by id) that are enabled for this data source. An 68 // empty filter implies all events are enabled. 69 EventFilter syscall_filter; 70 71 // Configuration of the optional compact encoding of scheduling events. 72 const CompactSchedConfig compact_sched; 73 74 // Optional configuration that's used to filter "ftrace/print" events based on 75 // the content of their "buf" field. 76 std::optional<FtracePrintFilterConfig> print_filter; 77 78 // Used only in Android for ATRACE_EVENT/os.Trace() userspace annotations. 79 std::vector<std::string> atrace_apps; 80 std::vector<std::string> atrace_categories; 81 82 // When enabled will turn on the kallsyms symbolizer in CpuReader. 83 const bool symbolize_ksyms; 84 85 // FtraceConfig.drain_buffer_percent for poll-based reads. Zero if unset. 86 const uint32_t buffer_percent; 87 88 // List of syscalls monitored to return a new filedescriptor upon success 89 base::FlatSet<int64_t> syscalls_returning_fd; 90 }; 91 92 // Ftrace is a bunch of globally modifiable persistent state. 93 // Given a number of FtraceConfig's we need to find the best union of all 94 // the settings to make everyone happy while also watching out for anybody 95 // messing with the ftrace settings at the same time as us. 96 // 97 // Specifically FtraceConfigMuxer takes in a *requested* FtraceConfig 98 // (|SetupConfig|), makes a best effort attempt to modify the ftrace 99 // debugfs files to honor those settings without interrupting other perfetto 100 // traces already in progress or other users of ftrace, then returns an 101 // FtraceConfigId representing that config or zero on failure. 102 // 103 // When you are finished with a config you can signal that with |RemoveConfig|. 104 class FtraceConfigMuxer { 105 public: 106 // The FtraceProcfs and ProtoTranslationTable 107 // should outlive this instance. 108 FtraceConfigMuxer( 109 FtraceProcfs* ftrace, 110 AtraceWrapper* atrace_wrapper, 111 ProtoTranslationTable* table, 112 SyscallTable syscalls, 113 std::map<std::string, std::vector<GroupAndName>> vendor_events, 114 bool secondary_instance = false); 115 virtual ~FtraceConfigMuxer(); 116 117 // Ask FtraceConfigMuxer to adjust ftrace procfs settings to 118 // match the requested config. Returns true on success and false on failure. 119 // This is best effort. FtraceConfigMuxer may not be able to adjust the 120 // buffer size right now. Events may be missing or there may be extra events 121 // (if you enable an atrace category we try to give you the matching events). 122 // If someone else is tracing we won't touch atrace (since it resets the 123 // buffer). 124 bool SetupConfig(FtraceConfigId id, 125 const FtraceConfig& request, 126 FtraceSetupErrors* = nullptr); 127 128 // Activate ftrace for the given config (if not already active). 129 bool ActivateConfig(FtraceConfigId); 130 131 // Undo changes for the given config. Returns false iff the id is 0 132 // or already removed. 133 bool RemoveConfig(FtraceConfigId); 134 135 const FtraceDataSourceConfig* GetDataSourceConfig(FtraceConfigId id); 136 137 // Resets the current tracer to "nop" (the default). This cannot be handled 138 // by |RemoveConfig| because it requires all ftrace readers to be released 139 // beforehand, which is the reponsibility of ftrace_controller. 140 bool ResetCurrentTracer(); 141 142 // Returns the current per-cpu buffer size, as configured by this muxer 143 // (without consulting debugfs). Constant for a given tracing session. 144 // Note that if there are multiple concurrent tracing sessions, the first 145 // session's buffer size is used for all of them. 146 size_t GetPerCpuBufferSizePages(); 147 ftrace_clock()148 protos::pbzero::FtraceClock ftrace_clock() const { 149 return current_state_.ftrace_clock; 150 } 151 SetupClockForTesting(const FtraceConfig & request)152 void SetupClockForTesting(const FtraceConfig& request) { 153 SetupClock(request); 154 } 155 GetFtraceEventsForTesting(const FtraceConfig & request,const ProtoTranslationTable * table)156 std::set<GroupAndName> GetFtraceEventsForTesting( 157 const FtraceConfig& request, 158 const ProtoTranslationTable* table) { 159 return GetFtraceEvents(request, table); 160 } 161 GetCentralEventFilterForTesting()162 const EventFilter* GetCentralEventFilterForTesting() const { 163 return ¤t_state_.ftrace_events; 164 } 165 GetSyscallFilterForTesting()166 const std::set<size_t>& GetSyscallFilterForTesting() const { 167 return current_state_.syscall_filter; 168 } 169 GetDataSourcesCount()170 size_t GetDataSourcesCount() const { return ds_configs_.size(); } 171 172 // Returns the syscall ids for the current architecture 173 // matching the (subjectively) most commonly used syscalls 174 // producing a new file descriptor as their return value. 175 static base::FlatSet<int64_t> GetSyscallsReturningFds( 176 const SyscallTable& syscalls); 177 178 private: 179 struct FtraceState { 180 EventFilter ftrace_events; 181 std::set<size_t> syscall_filter; // syscall ids or kAllSyscallsId 182 bool funcgraph_on = false; // current_tracer == "function_graph" 183 size_t cpu_buffer_size_pages = 0; 184 protos::pbzero::FtraceClock ftrace_clock{}; 185 // Used only in Android for ATRACE_EVENT/os.Trace() userspace: 186 bool atrace_on = false; 187 std::vector<std::string> atrace_apps; 188 std::vector<std::string> atrace_categories; 189 bool saved_tracing_on; // Backup for the original tracing_on. 190 }; 191 192 FtraceConfigMuxer(const FtraceConfigMuxer&) = delete; 193 FtraceConfigMuxer& operator=(const FtraceConfigMuxer&) = delete; 194 195 void SetupClock(const FtraceConfig& request); 196 void SetupBufferSize(const FtraceConfig& request); 197 bool UpdateBufferPercent(); 198 void UpdateAtrace(const FtraceConfig& request, std::string* atrace_errors); 199 bool StartAtrace(const std::vector<std::string>& apps, 200 const std::vector<std::string>& categories, 201 std::string* atrace_errors); 202 void DisableAtrace(); 203 204 // This processes the config to get the exact events. 205 // group/* -> Will read the fs and add all events in group. 206 // event -> Will look up the event to find the group. 207 // atrace category -> Will add events in that category. 208 std::set<GroupAndName> GetFtraceEvents(const FtraceConfig& request, 209 const ProtoTranslationTable*); 210 211 // Returns true if the event filter has at least one event from group. 212 bool FilterHasGroup(const EventFilter& filter, const std::string& group); 213 214 // Configs have three states: 215 // 1. The config does not include raw_syscall ftrace events (empty filter). 216 // 2. The config has at least one raw_syscall ftrace events, then either: 217 // a. The syscall_events is left empty (match all events). 218 // b. The syscall_events is non-empty (match only those events). 219 EventFilter BuildSyscallFilter(const EventFilter& ftrace_filter, 220 const FtraceConfig& request); 221 222 // Updates the ftrace syscall filters such that they satisfy all ds_configs_ 223 // and the extra_syscalls provided here. The filter is set to be the union of 224 // all configs meaning no config will lose events, but concurrent configs can 225 // see additional events. You may provide a syscall filter during SetUpConfig 226 // so the filter can be updated before ds_configs_. 227 bool SetSyscallEventFilter(const EventFilter& extra_syscalls); 228 229 FtraceProcfs* ftrace_; 230 AtraceWrapper* atrace_wrapper_; 231 ProtoTranslationTable* table_; 232 SyscallTable syscalls_; 233 234 FtraceState current_state_; 235 236 // Set of all requested tracing configurations, with the associated derived 237 // data used during parsing. Note that not all of these configurations might 238 // be active. When a config is present but not active, we do setup buffer 239 // sizes and events, but don't enable ftrace (i.e. tracing_on). 240 std::map<FtraceConfigId, FtraceDataSourceConfig> ds_configs_; 241 242 // Subset of |ds_configs_| that are currently active. At any time ftrace is 243 // enabled iff |active_configs_| is not empty. 244 std::set<FtraceConfigId> active_configs_; 245 246 std::map<std::string, std::vector<GroupAndName>> vendor_events_; 247 248 // If true, this muxer is for a secondary ftrace instance 249 // (tracefs/instances/<name>). At the moment, we only support basic ftrace 250 // event recording in such instances. So only |ftrace_events| and 251 // |ftrace_buffer_size| options are guaranteed to work. 252 bool secondary_instance_; 253 }; 254 255 size_t ComputeCpuBufferSizeInPages(size_t requested_buffer_size_kb, 256 bool buffer_size_lower_bound, 257 int64_t sysconf_phys_pages); 258 259 } // namespace perfetto 260 261 #endif // SRC_TRACED_PROBES_FTRACE_FTRACE_CONFIG_MUXER_H_ 262