LLDB mainline
DecodedThread.h
Go to the documentation of this file.
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"
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
22namespace lldb_private {
23namespace trace_intel_pt {
24
25/// Class for representing a libipt decoding error.
26class IntelPTError : public llvm::ErrorInfo<IntelPTError> {
27public:
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,
41
42 std::error_code convertToErrorCode() const override {
43 return llvm::errc::not_supported;
44 }
45
47
48 void log(llvm::raw_ostream &OS) const override;
49
50private:
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.
62class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
63public:
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 {
70 /// Number of trace items in this range.
71 uint64_t items_count;
72 /// Index of the first trace item in this range.
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.
84 /// The nanoseconds value for this range.
85 uint64_t nanos;
86 /// The corresponding TSC value for this range.
88 /// A nullable pointer to the 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.
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
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
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.
260
261 /// Append an instruction.
262 void AppendInstruction(const pt_insn &insn);
263
264private:
265 /// When adding new members to this class, make sure
266 /// to update \a CalculateApproximateMemoryUsage() accordingly.
268
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>
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.
315
316 /// Statistics of all tracing events.
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
325using 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
static llvm::raw_ostream & error(Stream &strm)
Class holding the instructions and function call hierarchy obtained from decoding a trace,...
Definition: DecodedThread.h:62
uint64_t m_insn_count
Total number of instructions in the trace.
const EventsStats & GetEventsStats() const
Return an object with statistics of the trace events that happened.
const ErrorStats & GetErrorStats() const
Return an object with statistics of the trace errors that happened.
std::optional< uint64_t > m_last_cpu
This is the chronologically last CPU ID.
std::optional< std::map< uint64_t, TSCRange >::iterator > m_last_tsc
This is the chronologically last TSC that has been added.
lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const
std::chrono::milliseconds m_total_decoding_time
Total amount of time spent decoding.
void AppendEvent(lldb::TraceEvent)
Append an event.
std::map< uint64_t, NanosecondsRange > m_nanoseconds
This map contains the non-interpolated nanoseconds timestamps of the decoded trace items.
llvm::StringRef GetErrorByIndex(uint64_t item_index) const
std::deque< TraceItemStorage > m_item_data
Most of the trace data is stored here.
EventsStats m_events_stats
Statistics of all tracing events.
lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const
llvm::DenseMap< uint64_t, lldb::addr_t > m_psb_offsets
std::optional< DecodedThread::NanosecondsRange > GetNanosecondsRangeByIndex(uint64_t item_index)
Get a maximal range of trace items that include the given item_index that have the same nanoseconds t...
void AppendError(const IntelPTError &error)
Append a decoding error.
lldb::TraceEvent GetEventByIndex(int item_index) const
void NotifyCPU(lldb::cpu_id_t cpu_id)
Notify this object that a CPU has been seen.
size_t CalculateApproximateMemoryUsage() const
The approximate size in bytes used by this instance, including all the already decoded instructions.
std::optional< LinuxPerfZeroTscConversion > m_tsc_conversion
TSC -> nanos conversion utility.
ErrorStats m_error_stats
Statistics of all tracing errors.
std::map< uint64_t, lldb::cpu_id_t > m_cpus
std::variant< std::string, lldb::TraceEvent, lldb::addr_t > TraceItemStorage
void NotifySyncPoint(lldb::addr_t psb_offset)
Notify this object that a new PSB has been seen.
std::optional< DecodedThread::TSCRange > GetTSCRangeByIndex(uint64_t item_index) const
Get a maximal range of trace items that include the given item_index that have the same TSC value.
DecodedThread::TraceItemStorage & CreateNewTraceItem(lldb::TraceItemKind kind, Data &&data)
Create a new trace item.
void AppendCustomError(llvm::StringRef error, bool fatal=false)
Append a custom decoding.
lldb::cpu_id_t GetCPUByIndex(uint64_t item_index) const
Get the most recent CPU id before or at the given trace item index.
void NotifyTsc(TSC tsc)
Notify this object that a new tsc has been seen.
lldb::addr_t GetSyncPointOffsetByIndex(uint64_t item_index) const
std::map< uint64_t, TSCRange > m_tscs
This map contains the TSCs of the decoded trace items.
uint64_t GetItemsCount() const
Get the total number of instruction, errors and events from the decoded trace.
lldb::ThreadSP m_thread_sp
When adding new members to this class, make sure to update CalculateApproximateMemoryUsage() accordin...
std::optional< std::map< uint64_t, NanosecondsRange >::iterator > m_last_nanoseconds
void AppendInstruction(const pt_insn &insn)
Append an instruction.
Class for representing a libipt decoding error.
Definition: DecodedThread.h:26
std::error_code convertToErrorCode() const override
Definition: DecodedThread.h:42
void log(llvm::raw_ostream &OS) const override
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:82
std::shared_ptr< DecodedThread > DecodedThreadSP
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
std::shared_ptr< lldb_private::Thread > ThreadSP
Definition: lldb-forward.h:438
TraceEvent
Events that might happen during a trace session.
uint32_t cpu_id_t
Definition: lldb-types.h:89
uint64_t addr_t
Definition: lldb-types.h:79
llvm::DenseMap< const char *, uint64_t > libipt_errors
uint64_t other_errors
The following counters are mutually exclusive.
std::unordered_map< lldb::TraceEvent, uint64_t > events_counts
A count for each individual event kind.
A structure that represents a maximal range of trace items associated to the same non-interpolated ti...
Definition: DecodedThread.h:83
NanosecondsRange * next_range
A nullable pointer to the next range.
Definition: DecodedThread.h:89
uint64_t first_item_index
Index of the first trace item in this range.
Definition: DecodedThread.h:93
double GetInterpolatedTime(uint64_t item_index, uint64_t beginning_of_time_nanos, const LinuxPerfZeroTscConversion &tsc_conversion) const
Calculate an interpolated timestamp in nanoseconds for the given item index.
TSC tsc
The corresponding TSC value for this range.
Definition: DecodedThread.h:87
uint64_t items_count
Number of trace items in this range.
Definition: DecodedThread.h:91
uint64_t nanos
The nanoseconds value for this range.
Definition: DecodedThread.h:85
A structure that represents a maximal range of trace items associated to the same TSC value.
Definition: DecodedThread.h:68
uint64_t items_count
Number of trace items in this range.
Definition: DecodedThread.h:71
uint64_t first_item_index
Index of the first trace item in this range.
Definition: DecodedThread.h:73