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