1 // Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROMIUMOS_WIDE_PROFILING_PERF_PARSER_H_ 6 #define CHROMIUMOS_WIDE_PROFILING_PERF_PARSER_H_ 7 8 #include <stdint.h> 9 10 #include <map> 11 #include <memory> 12 #include <set> 13 #include <string> 14 #include <unordered_map> 15 #include <utility> 16 #include <vector> 17 18 #include "base/macros.h" 19 20 #include "binary_data_utils.h" 21 #include "compat/proto.h" 22 #include "compat/string.h" 23 #include "dso.h" 24 #include "perf_reader.h" 25 26 namespace quipper { 27 28 using PerfEvent = PerfDataProto_PerfEvent; 29 30 // PID associated with the kernel mmap event. 31 const uint32_t kKernelPid = static_cast<uint32_t>(-1); 32 33 class AddressMapper; 34 class PerfDataProto_BranchStackEntry; 35 class PerfDataProto_CommEvent; 36 class PerfDataProto_ForkEvent; 37 class PerfDataProto_MMapEvent; 38 class PerfDataProto_PerfEvent; 39 40 struct ParsedEvent { 41 ParsedEvent() : command_(NULL) {} 42 43 // Stores address of the original PerfDataProto_PerfEvent owned by a 44 // PerfReader object. 45 PerfDataProto_PerfEvent* event_ptr; 46 47 // For mmap events, use this to count the number of samples that are in this 48 // region. 49 uint32_t num_samples_in_mmap_region; 50 51 // Command associated with this sample. 52 const string* command_; 53 54 // Accessor for command string. 55 const string command() const { 56 if (command_) return *command_; 57 return string(); 58 } 59 60 void set_command(const string* command) { command_ = command; } 61 62 // A struct that contains a DSO + offset pair. 63 struct DSOAndOffset { 64 const DSOInfo* dso_info_; 65 uint64_t offset_; 66 67 // Accessor methods. 68 const string dso_name() const { 69 if (dso_info_) return dso_info_->name; 70 return string(); 71 } 72 const string build_id() const { 73 if (dso_info_) return dso_info_->build_id; 74 return string(); 75 } 76 uint64_t offset() const { return offset_; } 77 78 DSOAndOffset() : dso_info_(NULL), offset_(0) {} 79 80 bool operator==(const DSOAndOffset& other) const { 81 return offset_ == other.offset_ && 82 !dso_name().compare(other.dso_name()) && 83 !build_id().compare(other.build_id()); 84 } 85 } dso_and_offset; 86 87 // DSO + offset info for callchain. 88 std::vector<DSOAndOffset> callchain; 89 90 // DSO + offset info for branch stack entries. 91 struct BranchEntry { 92 bool predicted; 93 DSOAndOffset from; 94 DSOAndOffset to; 95 96 bool operator==(const BranchEntry& other) const { 97 return predicted == other.predicted && from == other.from && 98 to == other.to; 99 } 100 }; 101 std::vector<BranchEntry> branch_stack; 102 103 // For comparing ParsedEvents. 104 bool operator==(const ParsedEvent& other) const { 105 return dso_and_offset == other.dso_and_offset && 106 std::equal(callchain.begin(), callchain.end(), 107 other.callchain.begin()) && 108 std::equal(branch_stack.begin(), branch_stack.end(), 109 other.branch_stack.begin()); 110 } 111 }; 112 113 struct PerfEventStats { 114 // Number of each type of event. 115 uint32_t num_sample_events; 116 uint32_t num_mmap_events; 117 uint32_t num_comm_events; 118 uint32_t num_fork_events; 119 uint32_t num_exit_events; 120 121 // Number of sample events that were successfully mapped using the address 122 // mapper. The mapping is recorded regardless of whether the address in the 123 // perf sample event itself was assigned the remapped address. The latter is 124 // indicated by |did_remap|. 125 uint32_t num_sample_events_mapped; 126 127 // Whether address remapping was enabled during event parsing. 128 bool did_remap; 129 }; 130 131 struct PerfParserOptions { 132 // For synthetic address mapping. 133 bool do_remap = false; 134 // Set this flag to discard non-sample events that don't have any associated 135 // sample events. e.g. MMAP regions with no samples in them. 136 bool discard_unused_events = false; 137 // When mapping perf sample events, at least this percentage of them must be 138 // successfully mapped in order for ProcessEvents() to return true. 139 // By default, most samples must be properly mapped in order for sample 140 // mapping to be considered successful. 141 float sample_mapping_percentage_threshold = 95.0f; 142 // Set this to sort perf events by time, assuming they have timestamps. 143 // PerfSerializer::serialize_sorted_events_, which is used by 144 // PerfSerializerTest. However, we should look at restructuring PerfParser not 145 // to need it, while still providing some PerfParserStats. 146 bool sort_events_by_time = true; 147 // If buildids are missing from the input data, they can be retrieved from 148 // the filesystem. 149 bool read_missing_buildids = false; 150 // Deduces file names and offsets for hugepage-backed mappings, as 151 // hugepage_text replaces these with anonymous mappings without filename or 152 // offset information.. 153 bool deduce_huge_page_mappings = true; 154 // Checks for split binary mappings and merges them when possible. This 155 // combines the split mappings into a single mapping so future consumers of 156 // the perf data will see a single mapping and not two or more distinct 157 // mappings. 158 bool combine_mappings = true; 159 }; 160 161 class PerfParser { 162 public: 163 explicit PerfParser(PerfReader* reader); 164 ~PerfParser(); 165 166 // Constructor that takes in options at PerfParser creation time. 167 explicit PerfParser(PerfReader* reader, const PerfParserOptions& options); 168 169 // Pass in a struct containing various options. 170 void set_options(const PerfParserOptions& options) { options_ = options; } 171 172 // Gets parsed event/sample info from raw event data. Stores pointers to the 173 // raw events in an array of ParsedEvents. Does not own the raw events. It is 174 // up to the user of this class to keep track of when these event pointers are 175 // invalidated. 176 bool ParseRawEvents(); 177 178 const std::vector<ParsedEvent>& parsed_events() const { 179 return parsed_events_; 180 } 181 182 const PerfEventStats& stats() const { return stats_; } 183 184 // Use with caution. Deserialization uses this to restore stats from proto. 185 PerfEventStats* mutable_stats() { return &stats_; } 186 187 private: 188 // Used for processing events. e.g. remapping with synthetic addresses. 189 bool ProcessEvents(); 190 191 // Used for processing user events. 192 bool ProcessUserEvents(PerfEvent& event); 193 194 // Looks up build IDs for all DSOs present in |reader_| by direct lookup using 195 // functions in dso.h. If there is a DSO with both an existing build ID and a 196 // new build ID read using dso.h, this will overwrite the existing build ID. 197 bool FillInDsoBuildIds(); 198 199 // Updates |reader_->events| based on the contents of |parsed_events_|. For 200 // example, if |parsed_events_| had some events removed or reordered, 201 // |reader_| would be updated to contain the new sequence of events. 202 void UpdatePerfEventsFromParsedEvents(); 203 204 // Does a sample event remap and then returns DSO name and offset of sample. 205 bool MapSampleEvent(ParsedEvent* parsed_event); 206 207 // Calls MapIPAndPidAndGetNameAndOffset() on the callchain of a sample event. 208 bool MapCallchain(const uint64_t ip, const PidTid pidtid, 209 uint64_t original_event_addr, 210 RepeatedField<uint64>* callchain, 211 ParsedEvent* parsed_event); 212 213 // Trims the branch stack for null entries and calls 214 // MapIPAndPidAndGetNameAndOffset() on each entry. 215 bool MapBranchStack( 216 const PidTid pidtid, 217 RepeatedPtrField<PerfDataProto_BranchStackEntry>* branch_stack, 218 ParsedEvent* parsed_event); 219 220 // This maps a sample event and returns the mapped address, DSO name, and 221 // offset within the DSO. This is a private function because the API might 222 // change in the future, and we don't want derived classes to be stuck with an 223 // obsolete API. 224 bool MapIPAndPidAndGetNameAndOffset( 225 uint64_t ip, const PidTid pidtid, uint64_t* new_ip, 226 ParsedEvent::DSOAndOffset* dso_and_offset); 227 228 // Parses a MMAP event. Adds the mapping to the AddressMapper of the event's 229 // process. If |options_.do_remap| is set, will update |event| with the 230 // remapped address. 231 bool MapMmapEvent(PerfDataProto_MMapEvent* event, uint64_t id); 232 233 // Processes a COMM event. Creates a new AddressMapper for the new command's 234 // process. 235 bool MapCommEvent(const PerfDataProto_CommEvent& event); 236 237 // Processes a FORK event. Creates a new AddressMapper for the PID of the new 238 // process, if none already exists. 239 bool MapForkEvent(const PerfDataProto_ForkEvent& event); 240 241 // Create a process mapper for a process. Optionally pass in a parent pid 242 // |ppid| from which to copy mappings. 243 // Returns (mapper, true) if a new AddressMapper was created, and 244 // (mapper, false) if there is an existing mapper. 245 std::pair<AddressMapper*, bool> GetOrCreateProcessMapper( 246 uint32_t pid, uint32_t ppid = kKernelPid); 247 248 // Points to a PerfReader that contains the input perf data to parse. 249 PerfReader* const reader_; 250 251 // Stores the output of ParseRawEvents(). Contains DSO + offset info for each 252 // event. 253 std::vector<ParsedEvent> parsed_events_; 254 255 // Store all option flags as one struct. 256 PerfParserOptions options_; 257 258 // Maps pid/tid to commands. 259 std::map<PidTid, const string*> pidtid_to_comm_map_; 260 261 // A set to store the actual command strings. 262 std::set<string> commands_; 263 264 // ParseRawEvents() records some statistics here. 265 PerfEventStats stats_; 266 267 // A set of unique DSOs that may be referenced by multiple events. 268 std::unordered_map<string, DSOInfo> name_to_dso_; 269 270 // Maps process ID to an address mapper for that process. 271 std::unordered_map<uint32_t, std::unique_ptr<AddressMapper>> process_mappers_; 272 273 DISALLOW_COPY_AND_ASSIGN(PerfParser); 274 }; 275 276 } // namespace quipper 277 278 #endif // CHROMIUMOS_WIDE_PROFILING_PERF_PARSER_H_ 279