// Copyright (c) 2013 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROMIUMOS_WIDE_PROFILING_PERF_PARSER_H_ #define CHROMIUMOS_WIDE_PROFILING_PERF_PARSER_H_ #include <stdint.h> #include <map> #include <set> #include <string> #include <utility> #include <vector> #include "base/macros.h" #include "perf_reader.h" #include "perf_utils.h" namespace quipper { class AddressMapper; // A struct containing all relevant info for a mapped DSO, independent of any // samples. struct DSOInfo { string name; string build_id; // Comparator that allows this to be stored in a STL set. bool operator<(const DSOInfo& other) const { if (name == other.name) return build_id < other.build_id; return name < other.name; } }; struct ParsedEvent { // TODO(sque): Turn this struct into a class to privatize member variables. ParsedEvent() : command_(NULL) {} // Stores address of an event_t owned by the |PerfReader::events_| vector. event_t* raw_event; // For mmap events, use this to count the number of samples that are in this // region. uint32_t num_samples_in_mmap_region; // Command associated with this sample. const string* command_; // Accessor for command string. const string command() const { if (command_) return *command_; return string(); } void set_command(const string* command) { command_ = command; } // A struct that contains a DSO + offset pair. struct DSOAndOffset { const DSOInfo* dso_info_; uint64_t offset_; // Accessor methods. const string dso_name() const { if (dso_info_) return dso_info_->name; return string(); } const string build_id() const { if (dso_info_) return dso_info_->build_id; return string(); } uint64_t offset() const { return offset_; } DSOAndOffset() : dso_info_(NULL), offset_(0) {} } dso_and_offset; // DSO+offset info for callchain. std::vector<DSOAndOffset> callchain; // DSO + offset info for branch stack entries. struct BranchEntry { bool predicted; DSOAndOffset from; DSOAndOffset to; }; std::vector<BranchEntry> branch_stack; }; struct PerfEventStats { // Number of each type of event. uint32_t num_sample_events; uint32_t num_mmap_events; uint32_t num_comm_events; uint32_t num_fork_events; uint32_t num_exit_events; // Number of sample events that were successfully mapped using the address // mapper. The mapping is recorded regardless of whether the address in the // perf sample event itself was assigned the remapped address. The latter is // indicated by |did_remap|. uint32_t num_sample_events_mapped; // Whether address remapping was enabled during event parsing. bool did_remap; }; class PerfParser : public PerfReader { public: PerfParser(); ~PerfParser(); struct Options { // For synthetic address mapping. bool do_remap = false; // Set this flag to discard non-sample events that don't have any associated // sample events. e.g. MMAP regions with no samples in them. bool discard_unused_events = false; // When mapping perf sample events, at least this percentage of them must be // successfully mapped in order for ProcessEvents() to return true. // By default, most samples must be properly mapped in order for sample // mapping to be considered successful. float sample_mapping_percentage_threshold = 95.0f; }; // Constructor that takes in options at PerfParser creation time. explicit PerfParser(const Options& options); // Pass in a struct containing various options. void set_options(const Options& options); // Gets parsed event/sample info from raw event data. bool ParseRawEvents(); const std::vector<ParsedEvent>& parsed_events() const { return parsed_events_; } // Returns an array of pointers to |parsed_events_| sorted by sample time. // The first time this is called, it will create the sorted array. const std::vector<ParsedEvent*>& GetEventsSortedByTime() const { return parsed_events_sorted_by_time_; } const PerfEventStats& stats() const { return stats_; } protected: // Defines a type for a pid:tid pair. typedef std::pair<uint32_t, uint32_t> PidTid; // Sort |parsed_events_| by time, storing the results in // |parsed_events_sorted_by_time_|. // Events can not be sorted by time if PERF_SAMPLE_TIME is not set in // attr.sample_type (PerfReader.sample_type_). In that case, // |parsed_events_sorted_by_time_| is not actually sorted, but has the same // order as |parsed_events_|. void MaybeSortParsedEvents(); // Used for processing events. e.g. remapping with synthetic addresses. bool ProcessEvents(); template <typename MMapEventT> bool MapMmapEvent(MMapEventT* event, uint64_t id) { return MapMmapEvent(id, event->pid, &event->start, &event->len, &event->pgoff); } bool MapMmapEvent(uint64_t id, uint32_t pid, uint64_t* p_start, uint64_t* p_len, uint64_t* p_pgoff); bool MapForkEvent(const struct fork_event& event); bool MapCommEvent(const struct comm_event& event); // Does a sample event remap and then returns DSO name and offset of sample. bool MapSampleEvent(ParsedEvent* parsed_event); std::vector<ParsedEvent> parsed_events_; // See MaybeSortParsedEvents to see why this might not actually be sorted // by time: std::vector<ParsedEvent*> parsed_events_sorted_by_time_; Options options_; // Store all option flags as one struct. // Maps pid/tid to commands. std::map<PidTid, const string*> pidtid_to_comm_map_; // A set to store the actual command strings. std::set<string> commands_; PerfEventStats stats_; // A set of unique DSOs that may be referenced by multiple events. std::set<DSOInfo> dso_set_; private: // Calls MapIPAndPidAndGetNameAndOffset() on the callchain of a sample event. bool MapCallchain(const uint64_t ip, const uint32_t pid, uint64_t original_event_addr, struct ip_callchain* callchain, ParsedEvent* parsed_event); // Trims the branch stack for null entries and calls // MapIPAndPidAndGetNameAndOffset() on each entry. bool MapBranchStack(const uint32_t pid, struct branch_stack* branch_stack, ParsedEvent* parsed_event); // This maps a sample event and returns the mapped address, DSO name, and // offset within the DSO. This is a private function because the API might // change in the future, and we don't want derived classes to be stuck with an // obsolete API. bool MapIPAndPidAndGetNameAndOffset( uint64_t ip, uint32_t pid, uint64_t* new_ip, ParsedEvent::DSOAndOffset* dso_and_offset); // Create a process mapper for a process. Optionally pass in a parent pid // |ppid| from which to copy mappings. // Returns (mapper, true) if a new AddressMapper was created, and // (mapper, false) if there is an existing mapper. std::pair<AddressMapper*, bool> GetOrCreateProcessMapper(uint32_t pid, uint32_t *ppid = NULL); std::unique_ptr<AddressMapper> kernel_mapper_; std::map<uint32_t, std::unique_ptr<AddressMapper>> process_mappers_; DISALLOW_COPY_AND_ASSIGN(PerfParser); }; } // namespace quipper #endif // CHROMIUMOS_WIDE_PROFILING_PERF_PARSER_H_