blob: a4d86fb48ebee00854387f40c3ae11f0123972db [file] [log] [blame]
//===-- TraceCursorIntelPT.cpp --------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "TraceCursorIntelPT.h"
#include "DecodedThread.h"
#include "TraceIntelPT.h"
#include <cstdlib>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::trace_intel_pt;
using namespace llvm;
TraceCursorIntelPT::TraceCursorIntelPT(
ThreadSP thread_sp, DecodedThreadSP decoded_thread_sp,
const Optional<LinuxPerfZeroTscConversion> &tsc_conversion,
Optional<uint64_t> beginning_of_time_nanos)
: TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp),
m_tsc_conversion(tsc_conversion),
m_beginning_of_time_nanos(beginning_of_time_nanos) {
Seek(0, SeekType::End);
}
void TraceCursorIntelPT::Next() {
m_pos += IsForwards() ? 1 : -1;
ClearTimingRangesIfInvalid();
}
void TraceCursorIntelPT::ClearTimingRangesIfInvalid() {
if (m_tsc_range_calculated) {
if (!m_tsc_range || m_pos < 0 || !m_tsc_range->InRange(m_pos)) {
m_tsc_range = None;
m_tsc_range_calculated = false;
}
}
if (m_nanoseconds_range_calculated) {
if (!m_nanoseconds_range || m_pos < 0 ||
!m_nanoseconds_range->InRange(m_pos)) {
m_nanoseconds_range = None;
m_nanoseconds_range_calculated = false;
}
}
}
const Optional<DecodedThread::TSCRange> &
TraceCursorIntelPT::GetTSCRange() const {
if (!m_tsc_range_calculated) {
m_tsc_range_calculated = true;
m_tsc_range = m_decoded_thread_sp->GetTSCRangeByIndex(m_pos);
}
return m_tsc_range;
}
const Optional<DecodedThread::NanosecondsRange> &
TraceCursorIntelPT::GetNanosecondsRange() const {
if (!m_nanoseconds_range_calculated) {
m_nanoseconds_range_calculated = true;
m_nanoseconds_range =
m_decoded_thread_sp->GetNanosecondsRangeByIndex(m_pos);
}
return m_nanoseconds_range;
}
bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
switch (origin) {
case TraceCursor::SeekType::Beginning:
m_pos = offset;
break;
case TraceCursor::SeekType::End:
m_pos = m_decoded_thread_sp->GetItemsCount() - 1 + offset;
break;
case TraceCursor::SeekType::Current:
m_pos += offset;
}
ClearTimingRangesIfInvalid();
return HasValue();
}
bool TraceCursorIntelPT::HasValue() const {
return m_pos >= 0 &&
static_cast<uint64_t>(m_pos) < m_decoded_thread_sp->GetItemsCount();
}
lldb::TraceItemKind TraceCursorIntelPT::GetItemKind() const {
return m_decoded_thread_sp->GetItemKindByIndex(m_pos);
}
const char *TraceCursorIntelPT::GetError() const {
return m_decoded_thread_sp->GetErrorByIndex(m_pos);
}
lldb::addr_t TraceCursorIntelPT::GetLoadAddress() const {
return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos);
}
Optional<uint64_t> TraceCursorIntelPT::GetHWClock() const {
if (const Optional<DecodedThread::TSCRange> &range = GetTSCRange())
return range->tsc;
return None;
}
Optional<double> TraceCursorIntelPT::GetWallClockTime() const {
if (const Optional<DecodedThread::NanosecondsRange> &range =
GetNanosecondsRange())
return range->GetInterpolatedTime(m_pos, *m_beginning_of_time_nanos,
*m_tsc_conversion);
return None;
}
Optional<lldb::cpu_id_t> TraceCursorIntelPT::GetCPU() const {
return m_decoded_thread_sp->GetCPUByIndex(m_pos);
}
lldb::TraceEvent TraceCursorIntelPT::GetEventType() const {
return m_decoded_thread_sp->GetEventByIndex(m_pos);
}
bool TraceCursorIntelPT::GoToId(user_id_t id) {
if (!HasId(id))
return false;
m_pos = id;
ClearTimingRangesIfInvalid();
return true;
}
bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const {
return id < m_decoded_thread_sp->GetItemsCount();
}
user_id_t TraceCursorIntelPT::GetId() const { return m_pos; }