// 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_