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#include <cstdlib>
13#include <optional>
14
15using namespace lldb;
16using namespace lldb_private;
17using namespace lldb_private::trace_intel_pt;
18using namespace llvm;
19
20TraceCursorIntelPT::TraceCursorIntelPT(
21 ThreadSP thread_sp, DecodedThreadSP decoded_thread_sp,
22 const std::optional<LinuxPerfZeroTscConversion> &tsc_conversion,
23 std::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(offset: 0, origin: lldb::eTraceCursorSeekTypeEnd);
28}
29
30void TraceCursorIntelPT::Next() {
31 m_pos += IsForwards() ? 1 : -1;
32 ClearTimingRangesIfInvalid();
33}
34
35void TraceCursorIntelPT::ClearTimingRangesIfInvalid() {
36 if (m_tsc_range_calculated) {
37 if (!m_tsc_range || m_pos < 0 || !m_tsc_range->InRange(item_index: m_pos)) {
38 m_tsc_range = std::nullopt;
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(item_index: m_pos)) {
46 m_nanoseconds_range = std::nullopt;
47 m_nanoseconds_range_calculated = false;
48 }
49 }
50}
51
52const std::optional<DecodedThread::TSCRange> &
53TraceCursorIntelPT::GetTSCRange() const {
54 if (!m_tsc_range_calculated) {
55 m_tsc_range_calculated = true;
56 m_tsc_range = m_decoded_thread_sp->GetTSCRangeByIndex(item_index: m_pos);
57 }
58 return m_tsc_range;
59}
60
61const std::optional<DecodedThread::NanosecondsRange> &
62TraceCursorIntelPT::GetNanosecondsRange() const {
63 if (!m_nanoseconds_range_calculated) {
64 m_nanoseconds_range_calculated = true;
65 m_nanoseconds_range =
66 m_decoded_thread_sp->GetNanosecondsRangeByIndex(item_index: m_pos);
67 }
68 return m_nanoseconds_range;
69}
70
71bool TraceCursorIntelPT::Seek(int64_t offset,
72 lldb::TraceCursorSeekType origin) {
73 switch (origin) {
74 case lldb::eTraceCursorSeekTypeBeginning:
75 m_pos = offset;
76 break;
77 case lldb::eTraceCursorSeekTypeEnd:
78 m_pos = m_decoded_thread_sp->GetItemsCount() - 1 + offset;
79 break;
80 case lldb::eTraceCursorSeekTypeCurrent:
81 m_pos += offset;
82 }
83
84 ClearTimingRangesIfInvalid();
85
86 return HasValue();
87}
88
89bool TraceCursorIntelPT::HasValue() const {
90 return m_pos >= 0 &&
91 static_cast<uint64_t>(m_pos) < m_decoded_thread_sp->GetItemsCount();
92}
93
94lldb::TraceItemKind TraceCursorIntelPT::GetItemKind() const {
95 return m_decoded_thread_sp->GetItemKindByIndex(item_index: m_pos);
96}
97
98llvm::StringRef TraceCursorIntelPT::GetError() const {
99 return m_decoded_thread_sp->GetErrorByIndex(item_index: m_pos);
100}
101
102lldb::addr_t TraceCursorIntelPT::GetLoadAddress() const {
103 return m_decoded_thread_sp->GetInstructionLoadAddress(item_index: m_pos);
104}
105
106std::optional<uint64_t> TraceCursorIntelPT::GetHWClock() const {
107 if (const std::optional<DecodedThread::TSCRange> &range = GetTSCRange())
108 return range->tsc;
109 return std::nullopt;
110}
111
112std::optional<double> TraceCursorIntelPT::GetWallClockTime() const {
113 if (const std::optional<DecodedThread::NanosecondsRange> &range =
114 GetNanosecondsRange())
115 return range->GetInterpolatedTime(item_index: m_pos, beginning_of_time_nanos: *m_beginning_of_time_nanos,
116 tsc_conversion: *m_tsc_conversion);
117 return std::nullopt;
118}
119
120lldb::cpu_id_t TraceCursorIntelPT::GetCPU() const {
121 return m_decoded_thread_sp->GetCPUByIndex(item_index: m_pos);
122}
123
124lldb::TraceEvent TraceCursorIntelPT::GetEventType() const {
125 return m_decoded_thread_sp->GetEventByIndex(item_index: m_pos);
126}
127
128bool TraceCursorIntelPT::GoToId(user_id_t id) {
129 if (!HasId(id))
130 return false;
131 m_pos = id;
132 ClearTimingRangesIfInvalid();
133 return true;
134}
135
136bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const {
137 return id < m_decoded_thread_sp->GetItemsCount();
138}
139
140user_id_t TraceCursorIntelPT::GetId() const { return m_pos; }
141
142std::optional<std::string> TraceCursorIntelPT::GetSyncPointMetadata() const {
143 return formatv(Fmt: "offset = 0x{0:x}",
144 Vals: m_decoded_thread_sp->GetSyncPointOffsetByIndex(item_index: m_pos))
145 .str();
146}
147

source code of lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp