Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
39645 views
1
//===-- DecodedThread.h -----------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
10
#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
11
12
#include "intel-pt.h"
13
#include "lldb/Target/Trace.h"
14
#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
15
#include "llvm/Support/Errc.h"
16
#include "llvm/Support/Error.h"
17
#include <deque>
18
#include <optional>
19
#include <utility>
20
#include <variant>
21
22
namespace lldb_private {
23
namespace trace_intel_pt {
24
25
/// Class for representing a libipt decoding error.
26
class IntelPTError : public llvm::ErrorInfo<IntelPTError> {
27
public:
28
static char ID;
29
30
/// \param[in] libipt_error_code
31
/// Negative number returned by libipt when decoding the trace and
32
/// signaling errors.
33
///
34
/// \param[in] address
35
/// Optional instruction address. When decoding an individual instruction,
36
/// its address might be available in the \a pt_insn object, and should be
37
/// passed to this constructor. Other errors don't have an associated
38
/// address.
39
IntelPTError(int libipt_error_code,
40
lldb::addr_t address = LLDB_INVALID_ADDRESS);
41
42
std::error_code convertToErrorCode() const override {
43
return llvm::errc::not_supported;
44
}
45
46
int GetLibiptErrorCode() const { return m_libipt_error_code; }
47
48
void log(llvm::raw_ostream &OS) const override;
49
50
private:
51
int m_libipt_error_code;
52
lldb::addr_t m_address;
53
};
54
55
/// \class DecodedThread
56
/// Class holding the instructions and function call hierarchy obtained from
57
/// decoding a trace, as well as a position cursor used when reverse debugging
58
/// the trace.
59
///
60
/// Each decoded thread contains a cursor to the current position the user is
61
/// stopped at. See \a Trace::GetCursorPosition for more information.
62
class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
63
public:
64
using TSC = uint64_t;
65
66
/// A structure that represents a maximal range of trace items associated to
67
/// the same TSC value.
68
struct TSCRange {
69
TSC tsc;
70
/// Number of trace items in this range.
71
uint64_t items_count;
72
/// Index of the first trace item in this range.
73
uint64_t first_item_index;
74
75
/// \return
76
/// \b true if and only if the given \p item_index is covered by this
77
/// range.
78
bool InRange(uint64_t item_index) const;
79
};
80
81
/// A structure that represents a maximal range of trace items associated to
82
/// the same non-interpolated timestamps in nanoseconds.
83
struct NanosecondsRange {
84
/// The nanoseconds value for this range.
85
uint64_t nanos;
86
/// The corresponding TSC value for this range.
87
TSC tsc;
88
/// A nullable pointer to the next range.
89
NanosecondsRange *next_range;
90
/// Number of trace items in this range.
91
uint64_t items_count;
92
/// Index of the first trace item in this range.
93
uint64_t first_item_index;
94
95
/// Calculate an interpolated timestamp in nanoseconds for the given item
96
/// index. It's guaranteed that two different item indices will produce
97
/// different interpolated values.
98
///
99
/// \param[in] item_index
100
/// The index of the item whose timestamp will be estimated. It has to be
101
/// part of this range.
102
///
103
/// \param[in] beginning_of_time_nanos
104
/// The timestamp at which tracing started.
105
///
106
/// \param[in] tsc_conversion
107
/// The tsc -> nanos conversion utility
108
///
109
/// \return
110
/// An interpolated timestamp value for the given trace item.
111
double
112
GetInterpolatedTime(uint64_t item_index, uint64_t beginning_of_time_nanos,
113
const LinuxPerfZeroTscConversion &tsc_conversion) const;
114
115
/// \return
116
/// \b true if and only if the given \p item_index is covered by this
117
/// range.
118
bool InRange(uint64_t item_index) const;
119
};
120
121
// Struct holding counts for events
122
struct EventsStats {
123
/// A count for each individual event kind. We use an unordered map instead
124
/// of a DenseMap because DenseMap can't understand enums.
125
///
126
/// Note: We can't use DenseMap because lldb::TraceEvent is not
127
/// automatically handled correctly by DenseMap. We'd need to implement a
128
/// custom DenseMapInfo struct for TraceEvent and that's a bit too much for
129
/// such a simple structure.
130
std::unordered_map<lldb::TraceEvent, uint64_t> events_counts;
131
uint64_t total_count = 0;
132
133
void RecordEvent(lldb::TraceEvent event);
134
};
135
136
// Struct holding counts for errors
137
struct ErrorStats {
138
/// The following counters are mutually exclusive
139
/// \{
140
uint64_t other_errors = 0;
141
uint64_t fatal_errors = 0;
142
// libipt error -> count
143
llvm::DenseMap<const char *, uint64_t> libipt_errors;
144
/// \}
145
146
uint64_t GetTotalCount() const;
147
148
void RecordError(int libipt_error_code);
149
150
void RecordError(bool fatal);
151
};
152
153
DecodedThread(
154
lldb::ThreadSP thread_sp,
155
const std::optional<LinuxPerfZeroTscConversion> &tsc_conversion);
156
157
/// Get the total number of instruction, errors and events from the decoded
158
/// trace.
159
uint64_t GetItemsCount() const;
160
161
/// \return
162
/// The error associated with a given trace item.
163
llvm::StringRef GetErrorByIndex(uint64_t item_index) const;
164
165
/// \return
166
/// The trace item kind given an item index.
167
lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const;
168
169
/// \return
170
/// The underlying event type for the given trace item index.
171
lldb::TraceEvent GetEventByIndex(int item_index) const;
172
173
/// Get the most recent CPU id before or at the given trace item index.
174
///
175
/// \param[in] item_index
176
/// The trace item index to compare with.
177
///
178
/// \return
179
/// The requested cpu id, or \a LLDB_INVALID_CPU_ID if not available.
180
lldb::cpu_id_t GetCPUByIndex(uint64_t item_index) const;
181
182
/// \return
183
/// The PSB offset associated with the given item index.
184
lldb::addr_t GetSyncPointOffsetByIndex(uint64_t item_index) const;
185
186
/// Get a maximal range of trace items that include the given \p item_index
187
/// that have the same TSC value.
188
///
189
/// \param[in] item_index
190
/// The trace item index to compare with.
191
///
192
/// \return
193
/// The requested TSC range, or \a std::nullopt if not available.
194
std::optional<DecodedThread::TSCRange>
195
GetTSCRangeByIndex(uint64_t item_index) const;
196
197
/// Get a maximal range of trace items that include the given \p item_index
198
/// that have the same nanoseconds timestamp without interpolation.
199
///
200
/// \param[in] item_index
201
/// The trace item index to compare with.
202
///
203
/// \return
204
/// The requested nanoseconds range, or \a std::nullopt if not available.
205
std::optional<DecodedThread::NanosecondsRange>
206
GetNanosecondsRangeByIndex(uint64_t item_index);
207
208
/// \return
209
/// The load address of the instruction at the given index.
210
lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const;
211
212
/// \return
213
/// The number of instructions in this trace (not trace items).
214
uint64_t GetTotalInstructionCount() const;
215
216
/// Return an object with statistics of the trace events that happened.
217
///
218
/// \return
219
/// The stats object of all the events.
220
const EventsStats &GetEventsStats() const;
221
222
/// Return an object with statistics of the trace errors that happened.
223
///
224
/// \return
225
/// The stats object of all the events.
226
const ErrorStats &GetErrorStats() const;
227
228
/// The approximate size in bytes used by this instance,
229
/// including all the already decoded instructions.
230
size_t CalculateApproximateMemoryUsage() const;
231
232
lldb::ThreadSP GetThread();
233
234
/// Notify this object that a new tsc has been seen.
235
/// If this a new TSC, an event will be created.
236
void NotifyTsc(TSC tsc);
237
238
/// Notify this object that a CPU has been seen.
239
/// If this a new CPU, an event will be created.
240
void NotifyCPU(lldb::cpu_id_t cpu_id);
241
242
/// Notify this object that a new PSB has been seen.
243
void NotifySyncPoint(lldb::addr_t psb_offset);
244
245
/// Append a decoding error.
246
void AppendError(const IntelPTError &error);
247
248
/// Append a custom decoding.
249
///
250
/// \param[in] error
251
/// The error message.
252
///
253
/// \param[in] fatal
254
/// If \b true, then the whole decoded thread should be discarded because a
255
/// fatal anomaly has been found.
256
void AppendCustomError(llvm::StringRef error, bool fatal = false);
257
258
/// Append an event.
259
void AppendEvent(lldb::TraceEvent);
260
261
/// Append an instruction.
262
void AppendInstruction(const pt_insn &insn);
263
264
private:
265
/// When adding new members to this class, make sure
266
/// to update \a CalculateApproximateMemoryUsage() accordingly.
267
lldb::ThreadSP m_thread_sp;
268
269
using TraceItemStorage =
270
std::variant<std::string, lldb::TraceEvent, lldb::addr_t>;
271
272
/// Create a new trace item.
273
///
274
/// \return
275
/// The index of the new item.
276
template <typename Data>
277
DecodedThread::TraceItemStorage &CreateNewTraceItem(lldb::TraceItemKind kind,
278
Data &&data);
279
280
/// Most of the trace data is stored here.
281
std::deque<TraceItemStorage> m_item_data;
282
283
/// This map contains the TSCs of the decoded trace items. It maps
284
/// `item index -> TSC`, where `item index` is the first index
285
/// at which the mapped TSC first appears. We use this representation because
286
/// TSCs are sporadic and we can think of them as ranges.
287
std::map<uint64_t, TSCRange> m_tscs;
288
/// This is the chronologically last TSC that has been added.
289
std::optional<std::map<uint64_t, TSCRange>::iterator> m_last_tsc =
290
std::nullopt;
291
/// This map contains the non-interpolated nanoseconds timestamps of the
292
/// decoded trace items. It maps `item index -> nanoseconds`, where `item
293
/// index` is the first index at which the mapped nanoseconds first appears.
294
/// We use this representation because timestamps are sporadic and we think of
295
/// them as ranges.
296
std::map<uint64_t, NanosecondsRange> m_nanoseconds;
297
std::optional<std::map<uint64_t, NanosecondsRange>::iterator>
298
m_last_nanoseconds = std::nullopt;
299
300
// The cpu information is stored as a map. It maps `item index -> CPU`.
301
// A CPU is associated with the next instructions that follow until the next
302
// cpu is seen.
303
std::map<uint64_t, lldb::cpu_id_t> m_cpus;
304
/// This is the chronologically last CPU ID.
305
std::optional<uint64_t> m_last_cpu;
306
307
// The PSB offsets are stored as a map. It maps `item index -> psb offset`.
308
llvm::DenseMap<uint64_t, lldb::addr_t> m_psb_offsets;
309
310
/// TSC -> nanos conversion utility.
311
std::optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
312
313
/// Statistics of all tracing errors.
314
ErrorStats m_error_stats;
315
316
/// Statistics of all tracing events.
317
EventsStats m_events_stats;
318
/// Total amount of time spent decoding.
319
std::chrono::milliseconds m_total_decoding_time{0};
320
321
/// Total number of instructions in the trace.
322
uint64_t m_insn_count = 0;
323
};
324
325
using DecodedThreadSP = std::shared_ptr<DecodedThread>;
326
327
} // namespace trace_intel_pt
328
} // namespace lldb_private
329
330
#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
331
332