Home | History | Annotate | Download | only in quipper
      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