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 <set>
22 
23 #include "src/traced/probes/ftrace/ftrace_config.h"
24 #include "src/traced/probes/ftrace/ftrace_controller.h"
25 #include "src/traced/probes/ftrace/ftrace_procfs.h"
26 #include "src/traced/probes/ftrace/proto_translation_table.h"
27 
28 namespace perfetto {
29 
30 // Ftrace is a bunch of globaly modifiable persistent state.
31 // Given a number of FtraceConfig's we need to find the best union of all
32 // the settings to make eveyone happy while also watching out for anybody
33 // messing with the ftrace settings at the same time as us.
34 
35 // Specifically FtraceConfigMuxer takes in a *requested* FtraceConfig
36 // (|SetupConfig|), makes a best effort attempt to modify the ftrace
37 // debugfs files to honor those settings without interupting other perfetto
38 // traces already in progress or other users of ftrace, then returns an
39 // FtraceConfigId representing that config or zero on failure.
40 
41 // To see which settings we actually managed to set you can call |GetConfig|
42 // and when you are finished with a config you can signal that with
43 // |RemoveConfig|.
44 class FtraceConfigMuxer {
45  public:
46   // The FtraceConfigMuxer and ProtoTranslationTable
47   // should outlive this instance.
48   FtraceConfigMuxer(FtraceProcfs* ftrace, ProtoTranslationTable* table);
49   virtual ~FtraceConfigMuxer();
50 
51   // Ask FtraceConfigMuxer to adjust ftrace procfs settings to
52   // match the requested config. Returns an id to manage this
53   // config or zero on failure.
54   // This is best effort. FtraceConfigMuxer may not be able to adjust the
55   // buffer size right now. Events may be missing or there may be extra events
56   // (if you enable an atrace catagory we try to give you the matching events).
57   // If someone else is tracing we won't touch atrace (since it resets the
58   // buffer).
59   // To see the config you ended up with use |GetConfig|.
60   FtraceConfigId SetupConfig(const FtraceConfig& request);
61 
62   // Activate ftrace for the given config (if not already active).
63   bool ActivateConfig(FtraceConfigId);
64 
65   // Undo changes for the given config. Returns false iff the id is 0
66   // or already removed.
67   bool RemoveConfig(FtraceConfigId);
68 
69   const EventFilter* GetEventFilter(FtraceConfigId id);
70 
71   // public for testing
SetupClockForTesting(const FtraceConfig & request)72   void SetupClockForTesting(const FtraceConfig& request) {
73     SetupClock(request);
74   }
75 
76   const FtraceConfig* GetConfigForTesting(FtraceConfigId id);
77 
GetFtraceEventsForTesting(const FtraceConfig & request,const ProtoTranslationTable * table)78   std::set<GroupAndName> GetFtraceEventsForTesting(
79       const FtraceConfig& request,
80       const ProtoTranslationTable* table) {
81     return GetFtraceEvents(request, table);
82   }
83 
84  private:
85   struct FtraceState {
86     EventFilter ftrace_events;
87     std::set<std::string> atrace_categories;
88     std::set<std::string> atrace_apps;
89     bool tracing_on = false;
90     bool atrace_on = false;
91     size_t cpu_buffer_size_pages = 0;
92   };
93 
94   FtraceConfigMuxer(const FtraceConfigMuxer&) = delete;
95   FtraceConfigMuxer& operator=(const FtraceConfigMuxer&) = delete;
96 
97   void SetupClock(const FtraceConfig& request);
98   void SetupBufferSize(const FtraceConfig& request);
99   void UpdateAtrace(const FtraceConfig& request);
100   void DisableAtrace();
101 
102   // This processes the config to get the exact events.
103   // group/* -> Will read the fs and add all events in group.
104   // event -> Will look up the event to find the group.
105   // atrace category -> Will add events in that category.
106   std::set<GroupAndName> GetFtraceEvents(const FtraceConfig& request,
107                                          const ProtoTranslationTable*);
108 
109   FtraceConfigId GetNextId();
110 
111   FtraceConfigId last_id_ = 1;
112   FtraceProcfs* ftrace_;
113   ProtoTranslationTable* table_;
114 
115   FtraceState current_state_;
116 
117   // There is a filter per config. These filters allow a quick way
118   // to check if a certain ftrace event with id x is enabled.
119   std::map<FtraceConfigId, EventFilter> filters_;
120 
121   // Set of all configurations. Note that not all of them might be active.
122   // When a config is present but not active, we do setup buffer sizes and
123   // events, but don't enable ftrace (i.e. tracing_on).
124   std::map<FtraceConfigId, FtraceConfig> configs_;
125 
126   // Subset of |configs_| that are currently active. At any time ftrace is
127   // enabled iff |active_configs_| is not empty.
128   std::set<FtraceConfigId> active_configs_;
129 };
130 
131 size_t ComputeCpuBufferSizeInPages(size_t requested_buffer_size_kb);
132 
133 }  // namespace perfetto
134 
135 #endif  // SRC_TRACED_PROBES_FTRACE_FTRACE_CONFIG_MUXER_H_
136