1fe6060f1SDimitry Andric //===-- TraceCursorIntelPT.cpp --------------------------------------------===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric
9fe6060f1SDimitry Andric #include "TraceCursorIntelPT.h"
10fe6060f1SDimitry Andric #include "DecodedThread.h"
11fe6060f1SDimitry Andric #include "TraceIntelPT.h"
12fe6060f1SDimitry Andric #include <cstdlib>
13bdd1243dSDimitry Andric #include <optional>
14fe6060f1SDimitry Andric
15fe6060f1SDimitry Andric using namespace lldb;
16fe6060f1SDimitry Andric using namespace lldb_private;
17fe6060f1SDimitry Andric using namespace lldb_private::trace_intel_pt;
18fe6060f1SDimitry Andric using namespace llvm;
19fe6060f1SDimitry Andric
TraceCursorIntelPT(ThreadSP thread_sp,DecodedThreadSP decoded_thread_sp,const std::optional<LinuxPerfZeroTscConversion> & tsc_conversion,std::optional<uint64_t> beginning_of_time_nanos)20972a253aSDimitry Andric TraceCursorIntelPT::TraceCursorIntelPT(
21972a253aSDimitry Andric ThreadSP thread_sp, DecodedThreadSP decoded_thread_sp,
22bdd1243dSDimitry Andric const std::optional<LinuxPerfZeroTscConversion> &tsc_conversion,
23bdd1243dSDimitry Andric std::optional<uint64_t> beginning_of_time_nanos)
24972a253aSDimitry Andric : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp),
25972a253aSDimitry Andric m_tsc_conversion(tsc_conversion),
26972a253aSDimitry Andric m_beginning_of_time_nanos(beginning_of_time_nanos) {
27bdd1243dSDimitry Andric Seek(0, lldb::eTraceCursorSeekTypeEnd);
28fe6060f1SDimitry Andric }
29fe6060f1SDimitry Andric
Next()3081ad6265SDimitry Andric void TraceCursorIntelPT::Next() {
31fe6060f1SDimitry Andric m_pos += IsForwards() ? 1 : -1;
32972a253aSDimitry Andric ClearTimingRangesIfInvalid();
33972a253aSDimitry Andric }
3481ad6265SDimitry Andric
ClearTimingRangesIfInvalid()35972a253aSDimitry Andric void TraceCursorIntelPT::ClearTimingRangesIfInvalid() {
36972a253aSDimitry Andric if (m_tsc_range_calculated) {
37972a253aSDimitry Andric if (!m_tsc_range || m_pos < 0 || !m_tsc_range->InRange(m_pos)) {
38*297eecfbSDimitry Andric m_tsc_range = std::nullopt;
39972a253aSDimitry Andric m_tsc_range_calculated = false;
40972a253aSDimitry Andric }
41972a253aSDimitry Andric }
4281ad6265SDimitry Andric
43972a253aSDimitry Andric if (m_nanoseconds_range_calculated) {
44972a253aSDimitry Andric if (!m_nanoseconds_range || m_pos < 0 ||
45972a253aSDimitry Andric !m_nanoseconds_range->InRange(m_pos)) {
46*297eecfbSDimitry Andric m_nanoseconds_range = std::nullopt;
47972a253aSDimitry Andric m_nanoseconds_range_calculated = false;
48972a253aSDimitry Andric }
49972a253aSDimitry Andric }
50972a253aSDimitry Andric }
51972a253aSDimitry Andric
52bdd1243dSDimitry Andric const std::optional<DecodedThread::TSCRange> &
GetTSCRange() const53972a253aSDimitry Andric TraceCursorIntelPT::GetTSCRange() const {
54972a253aSDimitry Andric if (!m_tsc_range_calculated) {
55972a253aSDimitry Andric m_tsc_range_calculated = true;
56972a253aSDimitry Andric m_tsc_range = m_decoded_thread_sp->GetTSCRangeByIndex(m_pos);
57972a253aSDimitry Andric }
58972a253aSDimitry Andric return m_tsc_range;
59972a253aSDimitry Andric }
60972a253aSDimitry Andric
61bdd1243dSDimitry Andric const std::optional<DecodedThread::NanosecondsRange> &
GetNanosecondsRange() const62972a253aSDimitry Andric TraceCursorIntelPT::GetNanosecondsRange() const {
63972a253aSDimitry Andric if (!m_nanoseconds_range_calculated) {
64972a253aSDimitry Andric m_nanoseconds_range_calculated = true;
65972a253aSDimitry Andric m_nanoseconds_range =
66972a253aSDimitry Andric m_decoded_thread_sp->GetNanosecondsRangeByIndex(m_pos);
67972a253aSDimitry Andric }
68972a253aSDimitry Andric return m_nanoseconds_range;
69fe6060f1SDimitry Andric }
70fe6060f1SDimitry Andric
Seek(int64_t offset,lldb::TraceCursorSeekType origin)71bdd1243dSDimitry Andric bool TraceCursorIntelPT::Seek(int64_t offset,
72bdd1243dSDimitry Andric lldb::TraceCursorSeekType origin) {
73fe6060f1SDimitry Andric switch (origin) {
74bdd1243dSDimitry Andric case lldb::eTraceCursorSeekTypeBeginning:
7581ad6265SDimitry Andric m_pos = offset;
7681ad6265SDimitry Andric break;
77bdd1243dSDimitry Andric case lldb::eTraceCursorSeekTypeEnd:
7881ad6265SDimitry Andric m_pos = m_decoded_thread_sp->GetItemsCount() - 1 + offset;
7981ad6265SDimitry Andric break;
80bdd1243dSDimitry Andric case lldb::eTraceCursorSeekTypeCurrent:
8181ad6265SDimitry Andric m_pos += offset;
8281ad6265SDimitry Andric }
83972a253aSDimitry Andric
84972a253aSDimitry Andric ClearTimingRangesIfInvalid();
8581ad6265SDimitry Andric
8681ad6265SDimitry Andric return HasValue();
8781ad6265SDimitry Andric }
8881ad6265SDimitry Andric
HasValue() const8981ad6265SDimitry Andric bool TraceCursorIntelPT::HasValue() const {
90972a253aSDimitry Andric return m_pos >= 0 &&
91972a253aSDimitry Andric static_cast<uint64_t>(m_pos) < m_decoded_thread_sp->GetItemsCount();
9281ad6265SDimitry Andric }
9381ad6265SDimitry Andric
GetItemKind() const9481ad6265SDimitry Andric lldb::TraceItemKind TraceCursorIntelPT::GetItemKind() const {
9581ad6265SDimitry Andric return m_decoded_thread_sp->GetItemKindByIndex(m_pos);
9681ad6265SDimitry Andric }
9781ad6265SDimitry Andric
GetError() const9806c3fb27SDimitry Andric llvm::StringRef TraceCursorIntelPT::GetError() const {
9981ad6265SDimitry Andric return m_decoded_thread_sp->GetErrorByIndex(m_pos);
10081ad6265SDimitry Andric }
10181ad6265SDimitry Andric
GetLoadAddress() const10281ad6265SDimitry Andric lldb::addr_t TraceCursorIntelPT::GetLoadAddress() const {
10381ad6265SDimitry Andric return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos);
10481ad6265SDimitry Andric }
10581ad6265SDimitry Andric
GetHWClock() const106bdd1243dSDimitry Andric std::optional<uint64_t> TraceCursorIntelPT::GetHWClock() const {
107bdd1243dSDimitry Andric if (const std::optional<DecodedThread::TSCRange> &range = GetTSCRange())
108972a253aSDimitry Andric return range->tsc;
109bdd1243dSDimitry Andric return std::nullopt;
110fe6060f1SDimitry Andric }
111972a253aSDimitry Andric
GetWallClockTime() const112bdd1243dSDimitry Andric std::optional<double> TraceCursorIntelPT::GetWallClockTime() const {
113bdd1243dSDimitry Andric if (const std::optional<DecodedThread::NanosecondsRange> &range =
114972a253aSDimitry Andric GetNanosecondsRange())
115972a253aSDimitry Andric return range->GetInterpolatedTime(m_pos, *m_beginning_of_time_nanos,
116972a253aSDimitry Andric *m_tsc_conversion);
117bdd1243dSDimitry Andric return std::nullopt;
118fe6060f1SDimitry Andric }
119fe6060f1SDimitry Andric
GetCPU() const120bdd1243dSDimitry Andric lldb::cpu_id_t TraceCursorIntelPT::GetCPU() const {
121753f127fSDimitry Andric return m_decoded_thread_sp->GetCPUByIndex(m_pos);
122753f127fSDimitry Andric }
123753f127fSDimitry Andric
GetEventType() const12481ad6265SDimitry Andric lldb::TraceEvent TraceCursorIntelPT::GetEventType() const {
12581ad6265SDimitry Andric return m_decoded_thread_sp->GetEventByIndex(m_pos);
126fe6060f1SDimitry Andric }
127fe6060f1SDimitry Andric
GoToId(user_id_t id)12881ad6265SDimitry Andric bool TraceCursorIntelPT::GoToId(user_id_t id) {
12981ad6265SDimitry Andric if (!HasId(id))
13081ad6265SDimitry Andric return false;
13181ad6265SDimitry Andric m_pos = id;
132972a253aSDimitry Andric ClearTimingRangesIfInvalid();
13381ad6265SDimitry Andric return true;
134fe6060f1SDimitry Andric }
135fe6060f1SDimitry Andric
HasId(lldb::user_id_t id) const13681ad6265SDimitry Andric bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const {
137972a253aSDimitry Andric return id < m_decoded_thread_sp->GetItemsCount();
138fe6060f1SDimitry Andric }
139fe6060f1SDimitry Andric
GetId() const14081ad6265SDimitry Andric user_id_t TraceCursorIntelPT::GetId() const { return m_pos; }
141bdd1243dSDimitry Andric
GetSyncPointMetadata() const142bdd1243dSDimitry Andric std::optional<std::string> TraceCursorIntelPT::GetSyncPointMetadata() const {
143bdd1243dSDimitry Andric return formatv("offset = 0x{0:x}",
144bdd1243dSDimitry Andric m_decoded_thread_sp->GetSyncPointOffsetByIndex(m_pos))
145bdd1243dSDimitry Andric .str();
146bdd1243dSDimitry Andric }
147