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 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 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(0, lldb::eTraceCursorSeekTypeEnd); 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 = 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(m_pos)) { 46 m_nanoseconds_range = std::nullopt; 47 m_nanoseconds_range_calculated = false; 48 } 49 } 50 } 51 52 const std::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 std::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, 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 89 bool TraceCursorIntelPT::HasValue() const { 90 return m_pos >= 0 && 91 static_cast<uint64_t>(m_pos) < m_decoded_thread_sp->GetItemsCount(); 92 } 93 94 lldb::TraceItemKind TraceCursorIntelPT::GetItemKind() const { 95 return m_decoded_thread_sp->GetItemKindByIndex(m_pos); 96 } 97 98 llvm::StringRef TraceCursorIntelPT::GetError() const { 99 return m_decoded_thread_sp->GetErrorByIndex(m_pos); 100 } 101 102 lldb::addr_t TraceCursorIntelPT::GetLoadAddress() const { 103 return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos); 104 } 105 106 std::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 112 std::optional<double> TraceCursorIntelPT::GetWallClockTime() const { 113 if (const std::optional<DecodedThread::NanosecondsRange> &range = 114 GetNanosecondsRange()) 115 return range->GetInterpolatedTime(m_pos, *m_beginning_of_time_nanos, 116 *m_tsc_conversion); 117 return std::nullopt; 118 } 119 120 lldb::cpu_id_t TraceCursorIntelPT::GetCPU() const { 121 return m_decoded_thread_sp->GetCPUByIndex(m_pos); 122 } 123 124 lldb::TraceEvent TraceCursorIntelPT::GetEventType() const { 125 return m_decoded_thread_sp->GetEventByIndex(m_pos); 126 } 127 128 bool TraceCursorIntelPT::GoToId(user_id_t id) { 129 if (!HasId(id)) 130 return false; 131 m_pos = id; 132 ClearTimingRangesIfInvalid(); 133 return true; 134 } 135 136 bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const { 137 return id < m_decoded_thread_sp->GetItemsCount(); 138 } 139 140 user_id_t TraceCursorIntelPT::GetId() const { return m_pos; } 141 142 std::optional<std::string> TraceCursorIntelPT::GetSyncPointMetadata() const { 143 return formatv("offset = 0x{0:x}", 144 m_decoded_thread_sp->GetSyncPointOffsetByIndex(m_pos)) 145 .str(); 146 } 147