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