1cfd96f05SWalter Erquinigo //===-- DecodedThread.cpp -------------------------------------------------===//
2cfd96f05SWalter Erquinigo //
3cfd96f05SWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4cfd96f05SWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information.
5cfd96f05SWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cfd96f05SWalter Erquinigo //
7cfd96f05SWalter Erquinigo //===----------------------------------------------------------------------===//
8cfd96f05SWalter Erquinigo 
9cfd96f05SWalter Erquinigo #include "DecodedThread.h"
10cfd96f05SWalter Erquinigo 
11b0aa7076SWalter Erquinigo #include <intel-pt.h>
12b0aa7076SWalter Erquinigo 
13b0aa7076SWalter Erquinigo #include "TraceCursorIntelPT.h"
146423b502SWalter Erquinigo 
156423b502SWalter Erquinigo #include <memory>
16cfd96f05SWalter Erquinigo 
17b0aa7076SWalter Erquinigo using namespace lldb;
18cfd96f05SWalter Erquinigo using namespace lldb_private;
19cfd96f05SWalter Erquinigo using namespace lldb_private::trace_intel_pt;
20cfd96f05SWalter Erquinigo using namespace llvm;
21cfd96f05SWalter Erquinigo 
IsLibiptError(int libipt_status)22059f39d2SWalter Erquinigo bool lldb_private::trace_intel_pt::IsLibiptError(int libipt_status) {
23059f39d2SWalter Erquinigo   return libipt_status < 0;
24059f39d2SWalter Erquinigo }
25059f39d2SWalter Erquinigo 
IsEndOfStream(int libipt_status)26059f39d2SWalter Erquinigo bool lldb_private::trace_intel_pt::IsEndOfStream(int libipt_status) {
27059f39d2SWalter Erquinigo   return libipt_status == -pte_eos;
28059f39d2SWalter Erquinigo }
29059f39d2SWalter Erquinigo 
IsTscUnavailable(int libipt_status)30059f39d2SWalter Erquinigo bool lldb_private::trace_intel_pt::IsTscUnavailable(int libipt_status) {
31059f39d2SWalter Erquinigo   return libipt_status == -pte_no_time;
32059f39d2SWalter Erquinigo }
33059f39d2SWalter Erquinigo 
34cfd96f05SWalter Erquinigo char IntelPTError::ID;
35cfd96f05SWalter Erquinigo 
IntelPTError(int libipt_error_code,lldb::addr_t address)36cfd96f05SWalter Erquinigo IntelPTError::IntelPTError(int libipt_error_code, lldb::addr_t address)
37cfd96f05SWalter Erquinigo     : m_libipt_error_code(libipt_error_code), m_address(address) {
38cfd96f05SWalter Erquinigo   assert(libipt_error_code < 0);
39cfd96f05SWalter Erquinigo }
40cfd96f05SWalter Erquinigo 
log(llvm::raw_ostream & OS) const41cfd96f05SWalter Erquinigo void IntelPTError::log(llvm::raw_ostream &OS) const {
42a7d6c3efSWalter Erquinigo   OS << pt_errstr(pt_errcode(m_libipt_error_code));
43a7d6c3efSWalter Erquinigo   if (m_address != LLDB_INVALID_ADDRESS && m_address > 0)
44a7d6c3efSWalter Erquinigo     OS << formatv(": {0:x+16}", m_address);
45cfd96f05SWalter Erquinigo }
46cfd96f05SWalter Erquinigo 
InRange(uint64_t item_index) const47*4f676c25SWalter Erquinigo bool DecodedThread::TSCRange::InRange(uint64_t item_index) const {
48*4f676c25SWalter Erquinigo   return item_index >= first_item_index &&
49*4f676c25SWalter Erquinigo          item_index < first_item_index + items_count;
50059f39d2SWalter Erquinigo }
51059f39d2SWalter Erquinigo 
InRange(uint64_t item_index) const52*4f676c25SWalter Erquinigo bool DecodedThread::NanosecondsRange::InRange(uint64_t item_index) const {
53*4f676c25SWalter Erquinigo   return item_index >= first_item_index &&
54*4f676c25SWalter Erquinigo          item_index < first_item_index + items_count;
55*4f676c25SWalter Erquinigo }
56*4f676c25SWalter Erquinigo 
GetInterpolatedTime(uint64_t item_index,uint64_t begin_of_time_nanos,const LinuxPerfZeroTscConversion & tsc_conversion) const57*4f676c25SWalter Erquinigo double DecodedThread::NanosecondsRange::GetInterpolatedTime(
58*4f676c25SWalter Erquinigo     uint64_t item_index, uint64_t begin_of_time_nanos,
59*4f676c25SWalter Erquinigo     const LinuxPerfZeroTscConversion &tsc_conversion) const {
60*4f676c25SWalter Erquinigo   uint64_t items_since_last_tsc = item_index - first_item_index;
61*4f676c25SWalter Erquinigo 
62*4f676c25SWalter Erquinigo   auto interpolate = [&](uint64_t next_range_start_ns) {
63*4f676c25SWalter Erquinigo     if (next_range_start_ns == nanos) {
64*4f676c25SWalter Erquinigo       // If the resolution of the conversion formula is bad enough to consider
65*4f676c25SWalter Erquinigo       // these two timestamps as equal, then we just increase the next one by 1
66*4f676c25SWalter Erquinigo       // for correction
67*4f676c25SWalter Erquinigo       next_range_start_ns++;
68*4f676c25SWalter Erquinigo     }
69*4f676c25SWalter Erquinigo     long double item_duration =
70*4f676c25SWalter Erquinigo         static_cast<long double>(items_count) / (next_range_start_ns - nanos);
71*4f676c25SWalter Erquinigo     return (nanos - begin_of_time_nanos) + items_since_last_tsc * item_duration;
72*4f676c25SWalter Erquinigo   };
73*4f676c25SWalter Erquinigo 
74*4f676c25SWalter Erquinigo   if (!next_range) {
75*4f676c25SWalter Erquinigo     // If this is the last TSC range, so we have to extrapolate. In this case,
76*4f676c25SWalter Erquinigo     // we assume that each instruction took one TSC, which is what an
77*4f676c25SWalter Erquinigo     // instruction would take if no parallelism is achieved and the frequency
78*4f676c25SWalter Erquinigo     // multiplier is 1.
79*4f676c25SWalter Erquinigo     return interpolate(tsc_conversion.ToNanos(tsc + items_count));
80*4f676c25SWalter Erquinigo   }
81*4f676c25SWalter Erquinigo   if (items_count < (next_range->tsc - tsc)) {
82*4f676c25SWalter Erquinigo     // If the numbers of items in this range is less than the total TSC duration
83*4f676c25SWalter Erquinigo     // of this range, i.e. each instruction taking longer than 1 TSC, then we
84*4f676c25SWalter Erquinigo     // can assume that something else happened between these TSCs (e.g. a
85*4f676c25SWalter Erquinigo     // context switch, change to kernel, decoding errors, etc). In this case, we
86*4f676c25SWalter Erquinigo     // also assume that each instruction took 1 TSC. A proper way to improve
87*4f676c25SWalter Erquinigo     // this would be to analize the next events in the trace looking for context
88*4f676c25SWalter Erquinigo     // switches or trace disablement events, but for now, as we only want an
89*4f676c25SWalter Erquinigo     // approximation, we keep it simple. We are also guaranteed that the time in
90*4f676c25SWalter Erquinigo     // nanos of the next range is different to the current one, just because of
91*4f676c25SWalter Erquinigo     // the definition of a NanosecondsRange.
92*4f676c25SWalter Erquinigo     return interpolate(
93*4f676c25SWalter Erquinigo         std::min(tsc_conversion.ToNanos(tsc + items_count), next_range->nanos));
94*4f676c25SWalter Erquinigo   }
95*4f676c25SWalter Erquinigo 
96*4f676c25SWalter Erquinigo   // In this case, each item took less than 1 TSC, so some parallelism was
97*4f676c25SWalter Erquinigo   // achieved, which is an indication that we didn't suffered of any kind of
98*4f676c25SWalter Erquinigo   // interruption.
99*4f676c25SWalter Erquinigo   return interpolate(next_range->nanos);
100*4f676c25SWalter Erquinigo }
101*4f676c25SWalter Erquinigo 
GetItemsCount() const102*4f676c25SWalter Erquinigo uint64_t DecodedThread::GetItemsCount() const { return m_item_kinds.size(); }
103*4f676c25SWalter Erquinigo 
104*4f676c25SWalter Erquinigo lldb::addr_t
GetInstructionLoadAddress(uint64_t item_index) const105*4f676c25SWalter Erquinigo DecodedThread::GetInstructionLoadAddress(uint64_t item_index) const {
106a7d6c3efSWalter Erquinigo   return m_item_data[item_index].load_address;
107cfd96f05SWalter Erquinigo }
108cfd96f05SWalter Erquinigo 
GetThread()109bcf1978aSAlisamar Husain ThreadSP DecodedThread::GetThread() { return m_thread_sp; }
110bcf1978aSAlisamar Husain 
111a7d6c3efSWalter Erquinigo DecodedThread::TraceItemStorage &
CreateNewTraceItem(lldb::TraceItemKind kind)112a7d6c3efSWalter Erquinigo DecodedThread::CreateNewTraceItem(lldb::TraceItemKind kind) {
113a7d6c3efSWalter Erquinigo   m_item_kinds.push_back(kind);
114a7d6c3efSWalter Erquinigo   m_item_data.emplace_back();
115*4f676c25SWalter Erquinigo   if (m_last_tsc)
116*4f676c25SWalter Erquinigo     (*m_last_tsc)->second.items_count++;
117*4f676c25SWalter Erquinigo   if (m_last_nanoseconds)
118*4f676c25SWalter Erquinigo     (*m_last_nanoseconds)->second.items_count++;
119a7d6c3efSWalter Erquinigo   return m_item_data.back();
120a7d6c3efSWalter Erquinigo }
121a7d6c3efSWalter Erquinigo 
NotifyTsc(TSC tsc)122*4f676c25SWalter Erquinigo void DecodedThread::NotifyTsc(TSC tsc) {
123*4f676c25SWalter Erquinigo   if (m_last_tsc && (*m_last_tsc)->second.tsc == tsc)
124*4f676c25SWalter Erquinigo     return;
125*4f676c25SWalter Erquinigo 
126*4f676c25SWalter Erquinigo   m_last_tsc =
127*4f676c25SWalter Erquinigo       m_tscs.emplace(GetItemsCount(), TSCRange{tsc, 0, GetItemsCount()}).first;
128*4f676c25SWalter Erquinigo 
129*4f676c25SWalter Erquinigo   if (m_tsc_conversion) {
130*4f676c25SWalter Erquinigo     uint64_t nanos = m_tsc_conversion->ToNanos(tsc);
131*4f676c25SWalter Erquinigo     if (!m_last_nanoseconds || (*m_last_nanoseconds)->second.nanos != nanos) {
132*4f676c25SWalter Erquinigo       m_last_nanoseconds =
133*4f676c25SWalter Erquinigo           m_nanoseconds
134*4f676c25SWalter Erquinigo               .emplace(GetItemsCount(), NanosecondsRange{nanos, tsc, nullptr, 0,
135*4f676c25SWalter Erquinigo                                                          GetItemsCount()})
136*4f676c25SWalter Erquinigo               .first;
137*4f676c25SWalter Erquinigo       if (*m_last_nanoseconds != m_nanoseconds.begin()) {
138*4f676c25SWalter Erquinigo         auto prev_range = prev(*m_last_nanoseconds);
139*4f676c25SWalter Erquinigo         prev_range->second.next_range = &(*m_last_nanoseconds)->second;
140ca922a35SAlisamar Husain       }
141ca922a35SAlisamar Husain     }
142*4f676c25SWalter Erquinigo   }
143*4f676c25SWalter Erquinigo   AppendEvent(lldb::eTraceEventHWClockTick);
144*4f676c25SWalter Erquinigo }
145ca922a35SAlisamar Husain 
NotifyCPU(lldb::cpu_id_t cpu_id)1464a843d92SWalter Erquinigo void DecodedThread::NotifyCPU(lldb::cpu_id_t cpu_id) {
1474a843d92SWalter Erquinigo   if (!m_last_cpu || *m_last_cpu != cpu_id) {
148*4f676c25SWalter Erquinigo     m_cpus.emplace(GetItemsCount(), cpu_id);
1494a843d92SWalter Erquinigo     m_last_cpu = cpu_id;
1504a843d92SWalter Erquinigo     AppendEvent(lldb::eTraceEventCPUChanged);
1514a843d92SWalter Erquinigo   }
1524a843d92SWalter Erquinigo }
1534a843d92SWalter Erquinigo 
1544a843d92SWalter Erquinigo Optional<lldb::cpu_id_t>
GetCPUByIndex(uint64_t item_index) const155*4f676c25SWalter Erquinigo DecodedThread::GetCPUByIndex(uint64_t item_index) const {
156*4f676c25SWalter Erquinigo   auto it = m_cpus.upper_bound(item_index);
1574a843d92SWalter Erquinigo   if (it == m_cpus.begin())
1584a843d92SWalter Erquinigo     return None;
1594a843d92SWalter Erquinigo   return prev(it)->second;
1604a843d92SWalter Erquinigo }
1614a843d92SWalter Erquinigo 
162*4f676c25SWalter Erquinigo Optional<DecodedThread::TSCRange>
GetTSCRangeByIndex(uint64_t item_index) const163*4f676c25SWalter Erquinigo DecodedThread::GetTSCRangeByIndex(uint64_t item_index) const {
164*4f676c25SWalter Erquinigo   auto next_it = m_tscs.upper_bound(item_index);
165*4f676c25SWalter Erquinigo   if (next_it == m_tscs.begin())
166*4f676c25SWalter Erquinigo     return None;
167*4f676c25SWalter Erquinigo   return prev(next_it)->second;
168*4f676c25SWalter Erquinigo }
169*4f676c25SWalter Erquinigo 
170*4f676c25SWalter Erquinigo Optional<DecodedThread::NanosecondsRange>
GetNanosecondsRangeByIndex(uint64_t item_index)171*4f676c25SWalter Erquinigo DecodedThread::GetNanosecondsRangeByIndex(uint64_t item_index) {
172*4f676c25SWalter Erquinigo   auto next_it = m_nanoseconds.upper_bound(item_index);
173*4f676c25SWalter Erquinigo   if (next_it == m_nanoseconds.begin())
174*4f676c25SWalter Erquinigo     return None;
175*4f676c25SWalter Erquinigo   return prev(next_it)->second;
176*4f676c25SWalter Erquinigo }
177*4f676c25SWalter Erquinigo 
AppendEvent(lldb::TraceEvent event)178a7d6c3efSWalter Erquinigo void DecodedThread::AppendEvent(lldb::TraceEvent event) {
179a7d6c3efSWalter Erquinigo   CreateNewTraceItem(lldb::eTraceItemKindEvent).event = event;
180a7d6c3efSWalter Erquinigo   m_events_stats.RecordEvent(event);
181a7d6c3efSWalter Erquinigo }
182a7d6c3efSWalter Erquinigo 
AppendInstruction(const pt_insn & insn)183a7d6c3efSWalter Erquinigo void DecodedThread::AppendInstruction(const pt_insn &insn) {
184a7d6c3efSWalter Erquinigo   CreateNewTraceItem(lldb::eTraceItemKindInstruction).load_address = insn.ip;
185a7d6c3efSWalter Erquinigo }
186a7d6c3efSWalter Erquinigo 
AppendError(const IntelPTError & error)187a7d6c3efSWalter Erquinigo void DecodedThread::AppendError(const IntelPTError &error) {
188059f39d2SWalter Erquinigo   // End of stream shouldn't be a public error
189a7d6c3efSWalter Erquinigo   if (IsEndOfStream(error.GetLibiptErrorCode()))
190059f39d2SWalter Erquinigo     return;
191a7d6c3efSWalter Erquinigo   CreateNewTraceItem(lldb::eTraceItemKindError).error =
192a7d6c3efSWalter Erquinigo       ConstString(error.message()).AsCString();
1931e5083a5SWalter Erquinigo }
1941e5083a5SWalter Erquinigo 
AppendCustomError(StringRef err)195a7d6c3efSWalter Erquinigo void DecodedThread::AppendCustomError(StringRef err) {
196a7d6c3efSWalter Erquinigo   CreateNewTraceItem(lldb::eTraceItemKindError).error =
197a7d6c3efSWalter Erquinigo       ConstString(err).AsCString();
1981e5083a5SWalter Erquinigo }
1991e5083a5SWalter Erquinigo 
GetEventByIndex(int item_index) const200a7d6c3efSWalter Erquinigo lldb::TraceEvent DecodedThread::GetEventByIndex(int item_index) const {
201a7d6c3efSWalter Erquinigo   return m_item_data[item_index].event;
202059f39d2SWalter Erquinigo }
203059f39d2SWalter Erquinigo 
RecordError(int libipt_error_code)204059f39d2SWalter Erquinigo void DecodedThread::LibiptErrorsStats::RecordError(int libipt_error_code) {
205059f39d2SWalter Erquinigo   libipt_errors_counts[pt_errstr(pt_errcode(libipt_error_code))]++;
2061e5083a5SWalter Erquinigo   total_count++;
2071e5083a5SWalter Erquinigo }
2081e5083a5SWalter Erquinigo 
RecordTscError(int libipt_error_code)2091e5083a5SWalter Erquinigo void DecodedThread::RecordTscError(int libipt_error_code) {
210059f39d2SWalter Erquinigo   m_tsc_errors_stats.RecordError(libipt_error_code);
2111e5083a5SWalter Erquinigo }
2121e5083a5SWalter Erquinigo 
213059f39d2SWalter Erquinigo const DecodedThread::LibiptErrorsStats &
GetTscErrorsStats() const214059f39d2SWalter Erquinigo DecodedThread::GetTscErrorsStats() const {
215059f39d2SWalter Erquinigo   return m_tsc_errors_stats;
216059f39d2SWalter Erquinigo }
217059f39d2SWalter Erquinigo 
GetEventsStats() const218059f39d2SWalter Erquinigo const DecodedThread::EventsStats &DecodedThread::GetEventsStats() const {
219059f39d2SWalter Erquinigo   return m_events_stats;
220059f39d2SWalter Erquinigo }
221059f39d2SWalter Erquinigo 
RecordEvent(lldb::TraceEvent event)222a7d6c3efSWalter Erquinigo void DecodedThread::EventsStats::RecordEvent(lldb::TraceEvent event) {
223059f39d2SWalter Erquinigo   events_counts[event]++;
224059f39d2SWalter Erquinigo   total_count++;
2251e5083a5SWalter Erquinigo }
2261e5083a5SWalter Erquinigo 
227*4f676c25SWalter Erquinigo lldb::TraceItemKind
GetItemKindByIndex(uint64_t item_index) const228*4f676c25SWalter Erquinigo DecodedThread::GetItemKindByIndex(uint64_t item_index) const {
229a7d6c3efSWalter Erquinigo   return static_cast<lldb::TraceItemKind>(m_item_kinds[item_index]);
230ca922a35SAlisamar Husain }
231ca922a35SAlisamar Husain 
GetErrorByIndex(uint64_t item_index) const232*4f676c25SWalter Erquinigo const char *DecodedThread::GetErrorByIndex(uint64_t item_index) const {
233a7d6c3efSWalter Erquinigo   return m_item_data[item_index].error;
234cfd96f05SWalter Erquinigo }
2350b697561SWalter Erquinigo 
DecodedThread(ThreadSP thread_sp,const llvm::Optional<LinuxPerfZeroTscConversion> & tsc_conversion)236*4f676c25SWalter Erquinigo DecodedThread::DecodedThread(
237*4f676c25SWalter Erquinigo     ThreadSP thread_sp,
238*4f676c25SWalter Erquinigo     const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion)
239*4f676c25SWalter Erquinigo     : m_thread_sp(thread_sp), m_tsc_conversion(tsc_conversion) {}
24037a466ddSAlisamar Husain 
CalculateApproximateMemoryUsage() const24137a466ddSAlisamar Husain size_t DecodedThread::CalculateApproximateMemoryUsage() const {
242a7d6c3efSWalter Erquinigo   return sizeof(TraceItemStorage) * m_item_data.size() +
243a7d6c3efSWalter Erquinigo          sizeof(uint8_t) * m_item_kinds.size() +
244*4f676c25SWalter Erquinigo          (sizeof(uint64_t) + sizeof(TSC)) * m_tscs.size() +
245*4f676c25SWalter Erquinigo          (sizeof(uint64_t) + sizeof(uint64_t)) * m_nanoseconds.size() +
246*4f676c25SWalter Erquinigo          (sizeof(uint64_t) + sizeof(lldb::cpu_id_t)) * m_cpus.size();
247ca922a35SAlisamar Husain }
248