You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
7.5 KiB
249 lines
7.5 KiB
// 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_
|
|
|