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