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 
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 
30 void TraceCursorIntelPT::Next() {
31   m_pos += IsForwards() ? 1 : -1;
32   ClearTimingRangesIfInvalid();
33 }
34 
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> &
53 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> &
62 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 
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 
88 bool TraceCursorIntelPT::HasValue() const {
89   return m_pos >= 0 &&
90          static_cast<uint64_t>(m_pos) < m_decoded_thread_sp->GetItemsCount();
91 }
92 
93 lldb::TraceItemKind TraceCursorIntelPT::GetItemKind() const {
94   return m_decoded_thread_sp->GetItemKindByIndex(m_pos);
95 }
96 
97 const char *TraceCursorIntelPT::GetError() const {
98   return m_decoded_thread_sp->GetErrorByIndex(m_pos);
99 }
100 
101 lldb::addr_t TraceCursorIntelPT::GetLoadAddress() const {
102   return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos);
103 }
104 
105 Optional<uint64_t> TraceCursorIntelPT::GetHWClock() const {
106   if (const Optional<DecodedThread::TSCRange> &range = GetTSCRange())
107     return range->tsc;
108   return None;
109 }
110 
111 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 
119 Optional<lldb::cpu_id_t> TraceCursorIntelPT::GetCPU() const {
120   return m_decoded_thread_sp->GetCPUByIndex(m_pos);
121 }
122 
123 lldb::TraceEvent TraceCursorIntelPT::GetEventType() const {
124   return m_decoded_thread_sp->GetEventByIndex(m_pos);
125 }
126 
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 
135 bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const {
136   return id < m_decoded_thread_sp->GetItemsCount();
137 }
138 
139 user_id_t TraceCursorIntelPT::GetId() const { return m_pos; }
140