xref: /aosp_15_r20/external/perfetto/src/traced/probes/ftrace/ftrace_config_muxer.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 &current_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