// 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 <memory> #include <set> #include <string> #include <unordered_map> #include <utility> #include <vector> #include "base/macros.h" #include "binary_data_utils.h" #include "compat/proto.h" #include "compat/string.h" #include "dso.h" #include "perf_reader.h" namespace quipper { using PerfEvent = PerfDataProto_PerfEvent; // PID associated with the kernel mmap event. const uint32_t kKernelPid = static_cast<uint32_t>(-1); class AddressMapper; class PerfDataProto_BranchStackEntry; class PerfDataProto_CommEvent; class PerfDataProto_ForkEvent; class PerfDataProto_MMapEvent; class PerfDataProto_PerfEvent; struct ParsedEvent { 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. // 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; // If buildids are missing from the input data, they can be retrieved from // the filesystem. bool read_missing_buildids = false; // Deduces file names and offsets for hugepage-backed mappings, as // hugepage_text replaces these with anonymous mappings without filename or // offset information.. bool deduce_huge_page_mappings = true; // Checks for split binary mappings and merges them when possible. This // combines the split mappings into a single mapping so future consumers of // the perf data will see a single mapping and not two or more distinct // mappings. bool combine_mappings = 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: // Used for processing events. e.g. remapping with synthetic addresses. bool ProcessEvents(); // Used for processing user events. bool ProcessUserEvents(PerfEvent& event); // Looks up build IDs for all DSOs present in |reader_| by direct lookup using // functions in dso.h. If there is a DSO with both an existing build ID and a // new build ID read using dso.h, this will overwrite the existing build ID. bool FillInDsoBuildIds(); // 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 PidTid pidtid, 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 PidTid pidtid, 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, const PidTid pidtid, 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 = kKernelPid); // 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::unordered_map<string, DSOInfo> name_to_dso_; // Maps process ID to an address mapper for that process. std::unordered_map<uint32_t, std::unique_ptr<AddressMapper>> process_mappers_; DISALLOW_COPY_AND_ASSIGN(PerfParser); }; } // namespace quipper #endif // CHROMIUMOS_WIDE_PROFILING_PERF_PARSER_H_