• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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_PROTO_TRANSLATION_TABLE_H_
18 #define SRC_TRACED_PROBES_FTRACE_PROTO_TRANSLATION_TABLE_H_
19 
20 #include <stdint.h>
21 
22 #include <deque>
23 #include <iostream>
24 #include <map>
25 #include <memory>
26 #include <set>
27 #include <string>
28 #include <vector>
29 
30 #include "perfetto/ext/base/scoped_file.h"
31 #include "src/traced/probes/ftrace/compact_sched.h"
32 #include "src/traced/probes/ftrace/event_info.h"
33 #include "src/traced/probes/ftrace/format_parser/format_parser.h"
34 #include "src/traced/probes/ftrace/printk_formats_parser.h"
35 
36 namespace perfetto {
37 
38 class FtraceProcfs;
39 
40 namespace protos {
41 namespace pbzero {
42 class FtraceEventBundle;
43 }  // namespace pbzero
44 }  // namespace protos
45 
46 // Used when reading the config to store the group and name info for the
47 // ftrace event.
48 class GroupAndName {
49  public:
GroupAndName(const std::string & group,const std::string & name)50   GroupAndName(const std::string& group, const std::string& name)
51       : group_(group), name_(name) {}
52 
53   bool operator==(const GroupAndName& other) const {
54     return std::tie(group_, name_) == std::tie(other.group(), other.name());
55   }
56 
57   bool operator<(const GroupAndName& other) const {
58     return std::tie(group_, name_) < std::tie(other.group(), other.name());
59   }
60 
name()61   const std::string& name() const { return name_; }
group()62   const std::string& group() const { return group_; }
63 
ToString()64   std::string ToString() const { return group_ + "/" + name_; }
65 
66  private:
67   std::string group_;
68   std::string name_;
69 };
70 
PrintTo(const GroupAndName & event,::std::ostream * os)71 inline void PrintTo(const GroupAndName& event, ::std::ostream* os) {
72   *os << "GroupAndName(" << event.group() << ", " << event.name() << ")";
73 }
74 
75 bool InferFtraceType(const std::string& type_and_name,
76                      size_t size,
77                      bool is_signed,
78                      FtraceFieldType* out);
79 
80 class ProtoTranslationTable {
81  public:
82   struct FtracePageHeaderSpec {
83     FtraceEvent::Field timestamp{};
84     FtraceEvent::Field overwrite{};
85     FtraceEvent::Field size{};
86   };
87 
88   static FtracePageHeaderSpec DefaultPageHeaderSpecForTesting();
89 
90   // This method mutates the |events| and |common_fields| vectors to
91   // fill some of the fields and to delete unused events/fields
92   // before std:move'ing them into the ProtoTranslationTable.
93   static std::unique_ptr<ProtoTranslationTable> Create(
94       const FtraceProcfs* ftrace_procfs,
95       std::vector<Event> events,
96       std::vector<Field> common_fields);
97   virtual ~ProtoTranslationTable();
98 
99   ProtoTranslationTable(const FtraceProcfs* ftrace_procfs,
100                         const std::vector<Event>& events,
101                         std::vector<Field> common_fields,
102                         FtracePageHeaderSpec ftrace_page_header_spec,
103                         CompactSchedEventFormat compact_sched_format,
104                         PrintkMap printk_formats);
105 
largest_id()106   size_t largest_id() const { return largest_id_; }
107 
common_fields()108   const std::vector<Field>& common_fields() const { return common_fields_; }
109 
110   // Virtual for testing.
GetEvent(const GroupAndName & group_and_name)111   virtual const Event* GetEvent(const GroupAndName& group_and_name) const {
112     if (!group_and_name_to_event_.count(group_and_name))
113       return nullptr;
114     return group_and_name_to_event_.at(group_and_name);
115   }
116 
GetEventsByGroup(const std::string & group)117   const std::vector<const Event*>* GetEventsByGroup(
118       const std::string& group) const {
119     if (!group_to_events_.count(group))
120       return nullptr;
121     return &group_to_events_.at(group);
122   }
123 
GetEventById(size_t id)124   const Event* GetEventById(size_t id) const {
125     if (id == 0 || id > largest_id_)
126       return nullptr;
127     const Event* evt = &events_[id];
128     if (!evt->ftrace_event_id)
129       return nullptr;
130     return evt;
131   }
132 
EventToFtraceId(const GroupAndName & group_and_name)133   size_t EventToFtraceId(const GroupAndName& group_and_name) const {
134     if (!group_and_name_to_event_.count(group_and_name))
135       return 0;
136     return group_and_name_to_event_.at(group_and_name)->ftrace_event_id;
137   }
138 
events()139   const std::deque<Event>& events() { return events_; }
ftrace_page_header_spec()140   const FtracePageHeaderSpec& ftrace_page_header_spec() const {
141     return ftrace_page_header_spec_;
142   }
143 
144   // Returns the size in bytes of the "size" field in the ftrace header. This
145   // usually matches sizeof(void*) in the kernel (which can be != sizeof(void*)
146   // of user space on 32bit-user + 64-bit-kernel configurations).
page_header_size_len()147   inline uint16_t page_header_size_len() const {
148     // TODO(fmayer): Do kernel deepdive to double check this.
149     return ftrace_page_header_spec_.size.size;
150   }
151 
152   // Retrieves the ftrace event from the proto translation
153   // table. If it does not exist, reads the format file and creates a
154   // new event with the proto id set to generic. Virtual for testing.
155   virtual const Event* GetOrCreateEvent(const GroupAndName&);
156 
157   // This is for backwards compatibility. If a group is not specified in the
158   // config then the first event with that name will be returned.
GetEventByName(const std::string & name)159   const Event* GetEventByName(const std::string& name) const {
160     if (!name_to_events_.count(name))
161       return nullptr;
162     return name_to_events_.at(name)[0];
163   }
164 
compact_sched_format()165   const CompactSchedEventFormat& compact_sched_format() const {
166     return compact_sched_format_;
167   }
168 
LookupTraceString(uint64_t address)169   base::StringView LookupTraceString(uint64_t address) const {
170     return printk_formats_.at(address);
171   }
172 
173  private:
174   ProtoTranslationTable(const ProtoTranslationTable&) = delete;
175   ProtoTranslationTable& operator=(const ProtoTranslationTable&) = delete;
176 
177   // Store strings so they can be read when writing the trace output.
178   const char* InternString(const std::string& str);
179 
180   uint16_t CreateGenericEventField(const FtraceEvent::Field& ftrace_field,
181                                    Event& event);
182 
183   const FtraceProcfs* ftrace_procfs_;
184   std::deque<Event> events_;
185   size_t largest_id_;
186   std::map<GroupAndName, const Event*> group_and_name_to_event_;
187   std::map<std::string, std::vector<const Event*>> name_to_events_;
188   std::map<std::string, std::vector<const Event*>> group_to_events_;
189   std::vector<Field> common_fields_;
190   FtracePageHeaderSpec ftrace_page_header_spec_{};
191   std::set<std::string> interned_strings_;
192   CompactSchedEventFormat compact_sched_format_;
193   PrintkMap printk_formats_;
194 };
195 
196 // Class for efficient 'is event with id x enabled?' checks.
197 // Mirrors the data in a FtraceConfig but in a format better suited
198 // to be consumed by CpuReader.
199 class EventFilter {
200  public:
201   EventFilter();
202   ~EventFilter();
203   EventFilter(EventFilter&&) = default;
204   EventFilter& operator=(EventFilter&&) = default;
205 
206   void AddEnabledEvent(size_t ftrace_event_id);
207   void DisableEvent(size_t ftrace_event_id);
208   bool IsEventEnabled(size_t ftrace_event_id) const;
209   std::set<size_t> GetEnabledEvents() const;
210   void EnableEventsFrom(const EventFilter&);
211 
212  private:
213   EventFilter(const EventFilter&) = delete;
214   EventFilter& operator=(const EventFilter&) = delete;
215 
216   std::vector<bool> enabled_ids_;
217 };
218 
219 }  // namespace perfetto
220 
221 #endif  // SRC_TRACED_PROBES_FTRACE_PROTO_TRANSLATION_TABLE_H_
222