-
Notifications
You must be signed in to change notification settings - Fork 55
/
perf_parser.h
299 lines (241 loc) · 10.6 KB
/
perf_parser.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
// 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 "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 std::string* command_;
// Accessor for command string.
const std::string command() const {
if (command_) return *command_;
return std::string();
}
void set_command(const std::string* command) { command_ = command; }
// A struct that contains a DSO + offset pair.
struct DSOAndOffset {
const DSOInfo* dso_info_;
uint64_t offset_;
// Accessor methods.
const std::string dso_name() const {
if (dso_info_) return dso_info_->name;
return std::string();
}
const std::string build_id() const {
if (dso_info_) return dso_info_->build_id;
return std::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 and offset information for data access address.
DSOAndOffset data_dso_and_offset;
// DSO + offset info for callchain.
std::vector<DSOAndOffset> callchain;
// DSO + offset info for branch stack entries.
struct BranchEntry {
bool mispredicted;
bool predicted;
bool in_transaction;
bool aborted_transaction;
uint16_t cycles;
DSOAndOffset from;
DSOAndOffset to;
bool operator==(const BranchEntry& other) const {
return mispredicted == other.mispredicted &&
predicted == other.predicted &&
in_transaction == other.in_transaction &&
aborted_transaction == other.aborted_transaction &&
cycles == other.cycles && 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 &&
data_dso_and_offset == other.data_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 whose code addresses 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;
// Number of sample events that contain data addresses and how many of these
// could be mapped using the address mapper.
uint32_t num_data_sample_events;
uint32_t num_data_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;
// Handle unaligned MMAP events emited by VMs that dynamically generate
// code objects.
bool allow_unaligned_jit_mappings = false;
};
class PerfParser {
public:
explicit PerfParser(PerfReader* reader);
~PerfParser();
// Constructor that takes in options at PerfParser creation time.
explicit PerfParser(PerfReader* reader, const PerfParserOptions& options);
PerfParser(const PerfParser&) = delete;
PerfParser& operator=(const PerfParser&) = delete;
// 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();
// Performs a sample event remap including for code and data addresses if
// present. It increments stats counters for samples that could be mapped,
// samples that include data, and samples with data that could be mapped.
void 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,
bool is_kernel);
// 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 std::string*> pidtid_to_comm_map_;
// A set to store the actual command strings.
std::set<std::string> commands_;
// ParseRawEvents() records some statistics here.
PerfEventStats stats_;
// A set of unique DSOs that may be referenced by multiple events.
std::unordered_map<std::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_;
};
} // namespace quipper
#endif // CHROMIUMOS_WIDE_PROFILING_PERF_PARSER_H_