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