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