1 //===-- TraceCursorIntelPT.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 "TraceCursorIntelPT.h"
10 #include "DecodedThread.h"
11 #include "TraceIntelPT.h"
12
13 #include <cstdlib>
14
15 using namespace lldb;
16 using namespace lldb_private;
17 using namespace lldb_private::trace_intel_pt;
18 using namespace llvm;
19
TraceCursorIntelPT(ThreadSP thread_sp,DecodedThreadSP decoded_thread_sp,const Optional<LinuxPerfZeroTscConversion> & tsc_conversion,Optional<uint64_t> beginning_of_time_nanos)20 TraceCursorIntelPT::TraceCursorIntelPT(
21 ThreadSP thread_sp, DecodedThreadSP decoded_thread_sp,
22 const Optional<LinuxPerfZeroTscConversion> &tsc_conversion,
23 Optional<uint64_t> beginning_of_time_nanos)
24 : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp),
25 m_tsc_conversion(tsc_conversion),
26 m_beginning_of_time_nanos(beginning_of_time_nanos) {
27 Seek(0, SeekType::End);
28 }
29
Next()30 void TraceCursorIntelPT::Next() {
31 m_pos += IsForwards() ? 1 : -1;
32 ClearTimingRangesIfInvalid();
33 }
34
ClearTimingRangesIfInvalid()35 void TraceCursorIntelPT::ClearTimingRangesIfInvalid() {
36 if (m_tsc_range_calculated) {
37 if (!m_tsc_range || m_pos < 0 || !m_tsc_range->InRange(m_pos)) {
38 m_tsc_range = None;
39 m_tsc_range_calculated = false;
40 }
41 }
42
43 if (m_nanoseconds_range_calculated) {
44 if (!m_nanoseconds_range || m_pos < 0 ||
45 !m_nanoseconds_range->InRange(m_pos)) {
46 m_nanoseconds_range = None;
47 m_nanoseconds_range_calculated = false;
48 }
49 }
50 }
51
52 const Optional<DecodedThread::TSCRange> &
GetTSCRange() const53 TraceCursorIntelPT::GetTSCRange() const {
54 if (!m_tsc_range_calculated) {
55 m_tsc_range_calculated = true;
56 m_tsc_range = m_decoded_thread_sp->GetTSCRangeByIndex(m_pos);
57 }
58 return m_tsc_range;
59 }
60
61 const Optional<DecodedThread::NanosecondsRange> &
GetNanosecondsRange() const62 TraceCursorIntelPT::GetNanosecondsRange() const {
63 if (!m_nanoseconds_range_calculated) {
64 m_nanoseconds_range_calculated = true;
65 m_nanoseconds_range =
66 m_decoded_thread_sp->GetNanosecondsRangeByIndex(m_pos);
67 }
68 return m_nanoseconds_range;
69 }
70
Seek(int64_t offset,SeekType origin)71 bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
72 switch (origin) {
73 case TraceCursor::SeekType::Beginning:
74 m_pos = offset;
75 break;
76 case TraceCursor::SeekType::End:
77 m_pos = m_decoded_thread_sp->GetItemsCount() - 1 + offset;
78 break;
79 case TraceCursor::SeekType::Current:
80 m_pos += offset;
81 }
82
83 ClearTimingRangesIfInvalid();
84
85 return HasValue();
86 }
87
HasValue() const88 bool TraceCursorIntelPT::HasValue() const {
89 return m_pos >= 0 &&
90 static_cast<uint64_t>(m_pos) < m_decoded_thread_sp->GetItemsCount();
91 }
92
GetItemKind() const93 lldb::TraceItemKind TraceCursorIntelPT::GetItemKind() const {
94 return m_decoded_thread_sp->GetItemKindByIndex(m_pos);
95 }
96
GetError() const97 const char *TraceCursorIntelPT::GetError() const {
98 return m_decoded_thread_sp->GetErrorByIndex(m_pos);
99 }
100
GetLoadAddress() const101 lldb::addr_t TraceCursorIntelPT::GetLoadAddress() const {
102 return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos);
103 }
104
GetHWClock() const105 Optional<uint64_t> TraceCursorIntelPT::GetHWClock() const {
106 if (const Optional<DecodedThread::TSCRange> &range = GetTSCRange())
107 return range->tsc;
108 return None;
109 }
110
GetWallClockTime() const111 Optional<double> TraceCursorIntelPT::GetWallClockTime() const {
112 if (const Optional<DecodedThread::NanosecondsRange> &range =
113 GetNanosecondsRange())
114 return range->GetInterpolatedTime(m_pos, *m_beginning_of_time_nanos,
115 *m_tsc_conversion);
116 return None;
117 }
118
GetCPU() const119 Optional<lldb::cpu_id_t> TraceCursorIntelPT::GetCPU() const {
120 return m_decoded_thread_sp->GetCPUByIndex(m_pos);
121 }
122
GetEventType() const123 lldb::TraceEvent TraceCursorIntelPT::GetEventType() const {
124 return m_decoded_thread_sp->GetEventByIndex(m_pos);
125 }
126
GoToId(user_id_t id)127 bool TraceCursorIntelPT::GoToId(user_id_t id) {
128 if (!HasId(id))
129 return false;
130 m_pos = id;
131 ClearTimingRangesIfInvalid();
132 return true;
133 }
134
HasId(lldb::user_id_t id) const135 bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const {
136 return id < m_decoded_thread_sp->GetItemsCount();
137 }
138
GetId() const139 user_id_t TraceCursorIntelPT::GetId() const { return m_pos; }
140