LLDB  mainline
DecodedThread.cpp
Go to the documentation of this file.
1 //===-- DecodedThread.cpp -------------------------------------------------===//
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 #include "DecodedThread.h"
10 #include "TraceCursorIntelPT.h"
11 #include <intel-pt.h>
12 #include <memory>
13 
14 using namespace lldb;
15 using namespace lldb_private;
16 using namespace lldb_private::trace_intel_pt;
17 using namespace llvm;
18 
19 char IntelPTError::ID;
20 
21 IntelPTError::IntelPTError(int libipt_error_code, lldb::addr_t address)
22  : m_libipt_error_code(libipt_error_code), m_address(address) {
23  assert(libipt_error_code < 0);
24 }
25 
26 void IntelPTError::log(llvm::raw_ostream &OS) const {
27  OS << pt_errstr(pt_errcode(m_libipt_error_code));
29  OS << formatv(": {0:x+16}", m_address);
30 }
31 
32 bool DecodedThread::TSCRange::InRange(uint64_t item_index) const {
33  return item_index >= first_item_index &&
34  item_index < first_item_index + items_count;
35 }
36 
37 bool DecodedThread::NanosecondsRange::InRange(uint64_t item_index) const {
38  return item_index >= first_item_index &&
39  item_index < first_item_index + items_count;
40 }
41 
43  uint64_t item_index, uint64_t begin_of_time_nanos,
44  const LinuxPerfZeroTscConversion &tsc_conversion) const {
45  uint64_t items_since_last_tsc = item_index - first_item_index;
46 
47  auto interpolate = [&](uint64_t next_range_start_ns) {
48  if (next_range_start_ns == nanos) {
49  // If the resolution of the conversion formula is bad enough to consider
50  // these two timestamps as equal, then we just increase the next one by 1
51  // for correction
52  next_range_start_ns++;
53  }
54  long double item_duration =
55  static_cast<long double>(items_count) / (next_range_start_ns - nanos);
56  return (nanos - begin_of_time_nanos) + items_since_last_tsc * item_duration;
57  };
58 
59  if (!next_range) {
60  // If this is the last TSC range, so we have to extrapolate. In this case,
61  // we assume that each instruction took one TSC, which is what an
62  // instruction would take if no parallelism is achieved and the frequency
63  // multiplier is 1.
64  return interpolate(tsc_conversion.ToNanos(tsc + items_count));
65  }
66  if (items_count < (next_range->tsc - tsc)) {
67  // If the numbers of items in this range is less than the total TSC duration
68  // of this range, i.e. each instruction taking longer than 1 TSC, then we
69  // can assume that something else happened between these TSCs (e.g. a
70  // context switch, change to kernel, decoding errors, etc). In this case, we
71  // also assume that each instruction took 1 TSC. A proper way to improve
72  // this would be to analize the next events in the trace looking for context
73  // switches or trace disablement events, but for now, as we only want an
74  // approximation, we keep it simple. We are also guaranteed that the time in
75  // nanos of the next range is different to the current one, just because of
76  // the definition of a NanosecondsRange.
77  return interpolate(
78  std::min(tsc_conversion.ToNanos(tsc + items_count), next_range->nanos));
79  }
80 
81  // In this case, each item took less than 1 TSC, so some parallelism was
82  // achieved, which is an indication that we didn't suffered of any kind of
83  // interruption.
84  return interpolate(next_range->nanos);
85 }
86 
87 uint64_t DecodedThread::GetItemsCount() const { return m_item_kinds.size(); }
88 
90 DecodedThread::GetInstructionLoadAddress(uint64_t item_index) const {
91  return m_item_data[item_index].load_address;
92 }
93 
95 DecodedThread::GetSyncPointOffsetByIndex(uint64_t item_index) const {
96  return m_psb_offsets.find(item_index)->second;
97 }
98 
99 ThreadSP DecodedThread::GetThread() { return m_thread_sp; }
100 
103  m_item_kinds.push_back(kind);
104  m_item_data.emplace_back();
105  if (m_last_tsc)
106  (*m_last_tsc)->second.items_count++;
107  if (m_last_nanoseconds)
108  (*m_last_nanoseconds)->second.items_count++;
109  return m_item_data.back();
110 }
111 
113  m_psb_offsets.try_emplace(GetItemsCount(), psb_offset);
115 }
116 
118  if (m_last_tsc && (*m_last_tsc)->second.tsc == tsc)
119  return;
120  if (m_last_tsc)
121  assert(tsc >= (*m_last_tsc)->second.tsc &&
122  "We can't have decreasing times");
123 
124  m_last_tsc =
125  m_tscs.emplace(GetItemsCount(), TSCRange{tsc, 0, GetItemsCount()}).first;
126 
127  if (m_tsc_conversion) {
128  uint64_t nanos = m_tsc_conversion->ToNanos(tsc);
129  if (!m_last_nanoseconds || (*m_last_nanoseconds)->second.nanos != nanos) {
132  .emplace(GetItemsCount(), NanosecondsRange{nanos, tsc, nullptr, 0,
133  GetItemsCount()})
134  .first;
135  if (*m_last_nanoseconds != m_nanoseconds.begin()) {
136  auto prev_range = prev(*m_last_nanoseconds);
137  prev_range->second.next_range = &(*m_last_nanoseconds)->second;
138  }
139  }
140  }
142 }
143 
145  if (!m_last_cpu || *m_last_cpu != cpu_id) {
146  m_cpus.emplace(GetItemsCount(), cpu_id);
147  m_last_cpu = cpu_id;
149  }
150 }
151 
152 lldb::cpu_id_t DecodedThread::GetCPUByIndex(uint64_t item_index) const {
153  auto it = m_cpus.upper_bound(item_index);
154  return it == m_cpus.begin() ? LLDB_INVALID_CPU_ID : prev(it)->second;
155 }
156 
157 Optional<DecodedThread::TSCRange>
158 DecodedThread::GetTSCRangeByIndex(uint64_t item_index) const {
159  auto next_it = m_tscs.upper_bound(item_index);
160  if (next_it == m_tscs.begin())
161  return None;
162  return prev(next_it)->second;
163 }
164 
165 Optional<DecodedThread::NanosecondsRange>
167  auto next_it = m_nanoseconds.upper_bound(item_index);
168  if (next_it == m_nanoseconds.begin())
169  return None;
170  return prev(next_it)->second;
171 }
172 
174  return m_insn_count;
175 }
176 
180 }
181 
182 void DecodedThread::AppendInstruction(const pt_insn &insn) {
184  m_insn_count++;
185 }
186 
189  ConstString(error.message()).AsCString();
190  m_error_stats.RecordError(/*fatal=*/false);
191 }
192 
193 void DecodedThread::AppendCustomError(StringRef err, bool fatal) {
195  ConstString(err).AsCString();
196  m_error_stats.RecordError(fatal);
197 }
198 
200  return m_item_data[item_index].event;
201 }
202 
204  return m_events_stats;
205 }
206 
208  events_counts[event]++;
209  total_count++;
210 }
211 
213  uint64_t total = 0;
214  for (const auto &[kind, count] : libipt_errors)
215  total += count;
216 
217  return total + other_errors + fatal_errors;
218 }
219 
221  if (fatal)
222  fatal_errors++;
223  else
224  other_errors++;
225 }
226 
227 void DecodedThread::ErrorStats::RecordError(int libipt_error_code) {
228  libipt_errors[pt_errstr(pt_errcode(libipt_error_code))]++;
229 }
230 
232  return m_error_stats;
233 }
234 
236 DecodedThread::GetItemKindByIndex(uint64_t item_index) const {
237  return static_cast<lldb::TraceItemKind>(m_item_kinds[item_index]);
238 }
239 
240 const char *DecodedThread::GetErrorByIndex(uint64_t item_index) const {
241  return m_item_data[item_index].error;
242 }
243 
245  ThreadSP thread_sp,
246  const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion)
247  : m_thread_sp(thread_sp), m_tsc_conversion(tsc_conversion) {}
248 
250  return sizeof(TraceItemStorage) * m_item_data.size() +
251  sizeof(uint8_t) * m_item_kinds.size() +
252  (sizeof(uint64_t) + sizeof(TSC)) * m_tscs.size() +
253  (sizeof(uint64_t) + sizeof(uint64_t)) * m_nanoseconds.size() +
254  (sizeof(uint64_t) + sizeof(lldb::cpu_id_t)) * m_cpus.size();
255 }
lldb::TraceItemKind
TraceItemKind
Definition: lldb-enumerations.h:1188
lldb_private::trace_intel_pt::DecodedThread::ErrorStats::GetTotalCount
uint64_t GetTotalCount() const
Definition: DecodedThread.cpp:212
lldb_private::trace_intel_pt::DecodedThread::AppendCustomError
void AppendCustomError(llvm::StringRef error, bool fatal=false)
Append a custom decoding.
Definition: DecodedThread.cpp:193
llvm
Definition: Debugger.h:50
lldb_private::trace_intel_pt::DecodedThread::NanosecondsRange::GetInterpolatedTime
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.
Definition: DecodedThread.cpp:42
lldb::eTraceItemKindError
@ eTraceItemKindError
Definition: lldb-enumerations.h:1189
lldb_private::trace_intel_pt::DecodedThread::GetNanosecondsRangeByIndex
llvm::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...
Definition: DecodedThread.cpp:166
lldb::eTraceItemKindInstruction
@ eTraceItemKindInstruction
Definition: lldb-enumerations.h:1191
lldb_private::trace_intel_pt::DecodedThread::DecodedThread
DecodedThread(lldb::ThreadSP thread_sp, const llvm::Optional< LinuxPerfZeroTscConversion > &tsc_conversion)
Definition: DecodedThread.cpp:244
lldb_private::trace_intel_pt::IntelPTError::m_libipt_error_code
int m_libipt_error_code
Definition: DecodedThread.h:49
lldb_private::trace_intel_pt::DecodedThread::CreateNewTraceItem
DecodedThread::TraceItemStorage & CreateNewTraceItem(lldb::TraceItemKind kind)
Create a new trace item.
Definition: DecodedThread.cpp:102
lldb_private::trace_intel_pt::IntelPTError::m_address
lldb::addr_t m_address
Definition: DecodedThread.h:50
TraceCursorIntelPT.h
lldb_private::trace_intel_pt::DecodedThread::AppendEvent
void AppendEvent(lldb::TraceEvent)
Append an event.
Definition: DecodedThread.cpp:177
lldb_private::trace_intel_pt::DecodedThread::GetCPUByIndex
lldb::cpu_id_t GetCPUByIndex(uint64_t item_index) const
Get the most recent CPU id before or at the given trace item index.
Definition: DecodedThread.cpp:152
lldb_private::trace_intel_pt::DecodedThread::NotifySyncPoint
void NotifySyncPoint(lldb::addr_t psb_offset)
Notify this object that a new PSB has been seen.
Definition: DecodedThread.cpp:112
lldb_private::ConstString::AsCString
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:192
lldb_private::trace_intel_pt::DecodedThread::GetTotalInstructionCount
uint64_t GetTotalInstructionCount() const
Definition: DecodedThread.cpp:173
lldb::addr_t
uint64_t addr_t
Definition: lldb-types.h:83
lldb_private::trace_intel_pt::DecodedThread::TraceItemStorage
We use a union to optimize the memory usage for the different kinds of trace items.
Definition: DecodedThread.h:269
lldb_private::trace_intel_pt::DecodedThread::GetItemsCount
uint64_t GetItemsCount() const
Get the total number of instruction, errors and events from the decoded trace.
Definition: DecodedThread.cpp:87
lldb_private::trace_intel_pt::DecodedThread::m_last_nanoseconds
llvm::Optional< std::map< uint64_t, NanosecondsRange >::iterator > m_last_nanoseconds
Definition: DecodedThread.h:307
lldb_private::trace_intel_pt::DecodedThread::GetInstructionLoadAddress
lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const
Definition: DecodedThread.cpp:90
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb::TraceEvent
TraceEvent
Events that might happen during a trace session.
Definition: lldb-enumerations.h:1172
lldb_private::trace_intel_pt::DecodedThread::TSCRange::items_count
uint64_t items_count
Number of trace items in this range.
Definition: DecodedThread.h:69
lldb_private::trace_intel_pt::DecodedThread::TSCRange::first_item_index
uint64_t first_item_index
Index of the first trace item in this range.
Definition: DecodedThread.h:71
ID
static char ID
Definition: IRDynamicChecks.cpp:33
lldb_private::trace_intel_pt::DecodedThread::m_item_data
std::vector< TraceItemStorage > m_item_data
Most of the trace data is stored here.
Definition: DecodedThread.h:287
lldb_private::trace_intel_pt::DecodedThread::AppendError
void AppendError(const IntelPTError &error)
Append a decoding error.
Definition: DecodedThread.cpp:187
lldb_private::trace_intel_pt::DecodedThread::TraceItemStorage::error
const char * error
The string message of this item if it's an error.
Definition: DecodedThread.h:277
DecodedThread.h
lldb::eTraceItemKindEvent
@ eTraceItemKindEvent
Definition: lldb-enumerations.h:1190
lldb_private::trace_intel_pt::DecodedThread::GetEventsStats
const EventsStats & GetEventsStats() const
Return an object with statistics of the trace events that happened.
Definition: DecodedThread.cpp:203
lldb_private::trace_intel_pt::DecodedThread::AppendInstruction
void AppendInstruction(const pt_insn &insn)
Append an instruction.
Definition: DecodedThread.cpp:182
lldb_private::ConstString
Definition: ConstString.h:39
lldb_private::trace_intel_pt::DecodedThread::NanosecondsRange::InRange
bool InRange(uint64_t item_index) const
Definition: DecodedThread.cpp:37
lldb_private::trace_intel_pt::DecodedThread::TSC
uint64_t TSC
Definition: DecodedThread.h:62
lldb_private::trace_intel_pt::DecodedThread::m_last_tsc
llvm::Optional< std::map< uint64_t, TSCRange >::iterator > m_last_tsc
This is the chronologically last TSC that has been added.
Definition: DecodedThread.h:298
lldb_private::trace_intel_pt::DecodedThread::GetItemKindByIndex
lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const
Definition: DecodedThread.cpp:236
lldb_private::trace_intel_pt::DecodedThread::GetErrorStats
const ErrorStats & GetErrorStats() const
Return an object with statistics of the trace errors that happened.
Definition: DecodedThread.cpp:231
lldb_private::trace_intel_pt::DecodedThread::TSCRange::InRange
bool InRange(uint64_t item_index) const
Definition: DecodedThread.cpp:32
lldb_private::trace_intel_pt::IntelPTError
Class for representing a libipt decoding error.
Definition: DecodedThread.h:24
lldb_private::trace_intel_pt::IntelPTError::log
void log(llvm::raw_ostream &OS) const override
Definition: DecodedThread.cpp:26
uint32_t
lldb::eTraceEventSyncPoint
@ eTraceEventSyncPoint
The underlying tracing technology emitted a synchronization event used by trace processors.
Definition: lldb-enumerations.h:1184
LLDB_INVALID_CPU_ID
#define LLDB_INVALID_CPU_ID
Definition: lldb-defines.h:89
lldb_private::trace_intel_pt::DecodedThread::NotifyTsc
void NotifyTsc(TSC tsc)
Notify this object that a new tsc has been seen.
Definition: DecodedThread.cpp:117
lldb_private::trace_intel_pt::DecodedThread::m_thread_sp
lldb::ThreadSP m_thread_sp
When adding new members to this class, make sure to update CalculateApproximateMemoryUsage() accordin...
Definition: DecodedThread.h:265
lldb_private::trace_intel_pt::DecodedThread::TraceItemStorage::event
lldb::TraceEvent event
The event kind of this item if it's an event.
Definition: DecodedThread.h:274
lldb_private::trace_intel_pt::DecodedThread::EventsStats::RecordEvent
void RecordEvent(lldb::TraceEvent event)
Definition: DecodedThread.cpp:207
lldb_private::trace_intel_pt::DecodedThread::ErrorStats
Definition: DecodedThread.h:135
lldb_private::LinuxPerfZeroTscConversion
jLLDBTraceGetState gdb-remote packet
Definition: TraceIntelPTGDBRemotePackets.h:89
lldb::eTraceEventCPUChanged
@ eTraceEventCPUChanged
Event due to CPU change for a thread.
Definition: lldb-enumerations.h:1179
lldb_private::trace_intel_pt::DecodedThread::m_tsc_conversion
llvm::Optional< LinuxPerfZeroTscConversion > m_tsc_conversion
TSC -> nanos conversion utility.
Definition: DecodedThread.h:320
lldb_private::trace_intel_pt::DecodedThread::CalculateApproximateMemoryUsage
size_t CalculateApproximateMemoryUsage() const
The approximate size in bytes used by this instance, including all the already decoded instructions.
Definition: DecodedThread.cpp:249
lldb_private::trace_intel_pt::DecodedThread::GetTSCRangeByIndex
llvm::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.
Definition: DecodedThread.cpp:158
lldb_private::trace_intel_pt::DecodedThread::EventsStats
Definition: DecodedThread.h:120
lldb_private::trace_intel_pt::DecodedThread::GetThread
lldb::ThreadSP GetThread()
Definition: DecodedThread.cpp:99
LLDB_INVALID_ADDRESS
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:74
lldb_private::trace_intel_pt::DecodedThread::NotifyCPU
void NotifyCPU(lldb::cpu_id_t cpu_id)
Notify this object that a CPU has been seen.
Definition: DecodedThread.cpp:144
lldb_private::LinuxPerfZeroTscConversion::ToNanos
uint64_t ToNanos(uint64_t tsc) const
Convert TSC value to nanosecond wall time.
Definition: TraceIntelPTGDBRemotePackets.cpp:75
lldb_private::trace_intel_pt::DecodedThread::m_cpus
std::map< uint64_t, lldb::cpu_id_t > m_cpus
Definition: DecodedThread.h:312
lldb_private::trace_intel_pt::DecodedThread::m_psb_offsets
llvm::DenseMap< uint64_t, lldb::addr_t > m_psb_offsets
Definition: DecodedThread.h:317
lldb_private::trace_intel_pt::DecodedThread::GetSyncPointOffsetByIndex
lldb::addr_t GetSyncPointOffsetByIndex(uint64_t item_index) const
Definition: DecodedThread.cpp:95
lldb_private::trace_intel_pt::DecodedThread::m_tscs
std::map< uint64_t, TSCRange > m_tscs
This map contains the TSCs of the decoded trace items.
Definition: DecodedThread.h:296
lldb_private::trace_intel_pt::DecodedThread::m_nanoseconds
std::map< uint64_t, NanosecondsRange > m_nanoseconds
This map contains the non-interpolated nanoseconds timestamps of the decoded trace items.
Definition: DecodedThread.h:305
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::trace_intel_pt
Definition: CommandObjectTraceStartIntelPT.h:18
lldb_private::trace_intel_pt::DecodedThread::NanosecondsRange
A structure that represents a maximal range of trace items associated to the same non-interpolated ti...
Definition: DecodedThread.h:81
lldb_private::trace_intel_pt::DecodedThread::m_item_kinds
std::vector< uint8_t > m_item_kinds
The TraceItemKind for each trace item encoded as uint8_t.
Definition: DecodedThread.h:290
lldb_private::trace_intel_pt::DecodedThread::m_insn_count
uint64_t m_insn_count
Total number of instructions in the trace.
Definition: DecodedThread.h:331
lldb::eTraceEventHWClockTick
@ eTraceEventHWClockTick
Event due to a CPU HW clock tick.
Definition: lldb-enumerations.h:1181
lldb_private::trace_intel_pt::DecodedThread::ErrorStats::RecordError
void RecordError(int libipt_error_code)
Definition: DecodedThread.cpp:227
lldb_private::trace_intel_pt::DecodedThread::TSCRange
A structure that represents a maximal range of trace items associated to the same TSC value.
Definition: DecodedThread.h:66
lldb_private::trace_intel_pt::DecodedThread::GetErrorByIndex
const char * GetErrorByIndex(uint64_t item_index) const
Definition: DecodedThread.cpp:240
lldb
Definition: SBAddress.h:15
lldb_private::trace_intel_pt::DecodedThread::TraceItemStorage::load_address
uint64_t load_address
The load addresses of this item if it's an instruction.
Definition: DecodedThread.h:271
lldb_private::trace_intel_pt::DecodedThread::m_error_stats
ErrorStats m_error_stats
Statistics of all tracing errors.
Definition: DecodedThread.h:323
lldb_private::trace_intel_pt::DecodedThread::m_last_cpu
llvm::Optional< uint64_t > m_last_cpu
This is the chronologically last CPU ID.
Definition: DecodedThread.h:314
lldb_private::trace_intel_pt::DecodedThread::m_events_stats
EventsStats m_events_stats
Statistics of all tracing events.
Definition: DecodedThread.h:326
lldb_private::trace_intel_pt::DecodedThread::GetEventByIndex
lldb::TraceEvent GetEventByIndex(int item_index) const
Definition: DecodedThread.cpp:199
lldb_private::LLDBLog::OS
@ OS