| // 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 "chromiumos-wide-profiling/compat/proto.h" |
| #include "chromiumos-wide-profiling/compat/string.h" |
| #include "chromiumos-wide-profiling/perf_reader.h" |
| #include "chromiumos-wide-profiling/utils.h" |
| |
| namespace quipper { |
| |
| class AddressMapper; |
| class PerfDataProto_BranchStackEntry; |
| class PerfDataProto_CommEvent; |
| class PerfDataProto_ForkEvent; |
| class PerfDataProto_MMapEvent; |
| class PerfDataProto_PerfEvent; |
| |
| // 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 { |
| return name < other.name; |
| } |
| }; |
| |
| struct ParsedEvent { |
| // TODO(sque): Turn this struct into a class to privatize member variables. |
| ParsedEvent() : command_(NULL) {} |
| |
| // Stores address of the original PerfDataProto_PerfEvent owned by a |
| // PerfReader object. |
| PerfDataProto_PerfEvent* event_ptr; |
| |
| // 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) {} |
| |
| bool operator == (const DSOAndOffset& other) const { |
| return offset_ == other.offset_ && |
| !dso_name().compare(other.dso_name()) && |
| !build_id().compare(other.build_id()); |
| } |
| } 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; |
| |
| bool operator == (const BranchEntry& other) const { |
| return predicted == other.predicted && |
| from == other.from && |
| to == other.to; |
| } |
| }; |
| std::vector<BranchEntry> branch_stack; |
| |
| // For comparing ParsedEvents. |
| bool operator == (const ParsedEvent& other) const { |
| return dso_and_offset == other.dso_and_offset && |
| std::equal(callchain.begin(), callchain.end(), |
| other.callchain.begin()) && |
| std::equal(branch_stack.begin(), branch_stack.end(), |
| other.branch_stack.begin()); |
| } |
| }; |
| |
| 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; |
| }; |
| |
| struct PerfParserOptions { |
| // 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; |
| // Set this to sort perf events by time, assuming they have timestamps. |
| // TODO(sque): This is to maintain the legacy feature of |
| // PerfSerializer::serialize_sorted_events_, which is used by |
| // PerfSerializerTest. However, we should look at restructuring PerfParser not |
| // to need it, while still providing some PerfParserStats. |
| bool sort_events_by_time = true; |
| }; |
| |
| class PerfParser { |
| public: |
| explicit PerfParser(PerfReader* reader); |
| ~PerfParser(); |
| |
| // Constructor that takes in options at PerfParser creation time. |
| explicit PerfParser(PerfReader* reader, const PerfParserOptions& options); |
| |
| // Pass in a struct containing various options. |
| void set_options(const PerfParserOptions& options) { |
| options_ = options; |
| } |
| |
| // Gets parsed event/sample info from raw event data. Stores pointers to the |
| // raw events in an array of ParsedEvents. Does not own the raw events. It is |
| // up to the user of this class to keep track of when these event pointers are |
| // invalidated. |
| bool ParseRawEvents(); |
| |
| const std::vector<ParsedEvent>& parsed_events() const { |
| return parsed_events_; |
| } |
| |
| const PerfEventStats& stats() const { |
| return stats_; |
| } |
| |
| // Use with caution. Deserialization uses this to restore stats from proto. |
| PerfEventStats* mutable_stats() { |
| return &stats_; |
| } |
| |
| private: |
| // Defines a type for a pid:tid pair. |
| typedef std::pair<uint32_t, uint32_t> PidTid; |
| |
| // Used for processing events. e.g. remapping with synthetic addresses. |
| bool ProcessEvents(); |
| |
| // Sort |parsed_events_| by time, and updates the events in |reader_| in |
| // sorted order. |
| // Events can not be sorted by time if PERF_SAMPLE_TIME is not set in |
| // attr.sample_type for all attrs. |
| void MaybeSortParsedEvents(); |
| |
| // Updates |reader_->events| based on the contents of |parsed_events_|. For |
| // example, if |parsed_events_| had some events removed or reordered, |
| // |reader_| would be updated to contain the new sequence of events. |
| void UpdatePerfEventsFromParsedEvents(); |
| |
| // Does a sample event remap and then returns DSO name and offset of sample. |
| bool MapSampleEvent(ParsedEvent* parsed_event); |
| |
| // Calls MapIPAndPidAndGetNameAndOffset() on the callchain of a sample event. |
| bool MapCallchain(const uint64_t ip, |
| const uint32_t pid, |
| uint64_t original_event_addr, |
| RepeatedField<uint64>* callchain, |
| ParsedEvent* parsed_event); |
| |
| // Trims the branch stack for null entries and calls |
| // MapIPAndPidAndGetNameAndOffset() on each entry. |
| bool MapBranchStack( |
| const uint32_t pid, |
| RepeatedPtrField<PerfDataProto_BranchStackEntry>* 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); |
| |
| // Parses a MMAP event. Adds the mapping to the AddressMapper of the event's |
| // process. If |options_.do_remap| is set, will update |event| with the |
| // remapped address. |
| bool MapMmapEvent(PerfDataProto_MMapEvent* event, uint64_t id); |
| |
| // Processes a COMM event. Creates a new AddressMapper for the new command's |
| // process. |
| bool MapCommEvent(const PerfDataProto_CommEvent& event); |
| |
| // Processes a FORK event. Creates a new AddressMapper for the PID of the new |
| // process, if none already exists. |
| bool MapForkEvent(const PerfDataProto_ForkEvent& event); |
| |
| // 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 = -1); |
| |
| // Points to a PerfReader that contains the input perf data to parse. |
| PerfReader* const reader_; |
| |
| // Stores the output of ParseRawEvents(). Contains DSO + offset info for each |
| // event. |
| std::vector<ParsedEvent> parsed_events_; |
| |
| // Store all option flags as one struct. |
| PerfParserOptions options_; |
| |
| // 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_; |
| |
| // ParseRawEvents() records some statistics here. |
| PerfEventStats stats_; |
| |
| // A set of unique DSOs that may be referenced by multiple events. |
| std::set<DSOInfo> dso_set_; |
| |
| // Maps process ID to an address mapper for that process. |
| std::map<uint32_t, std::unique_ptr<AddressMapper>> process_mappers_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PerfParser); |
| }; |
| |
| } // namespace quipper |
| |
| #endif // CHROMIUMOS_WIDE_PROFILING_PERF_PARSER_H_ |