aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp')
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp219
1 files changed, 153 insertions, 66 deletions
diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
index 4822a786c68c..578828ff1633 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
@@ -9,16 +9,28 @@
#include "DecodedThread.h"
#include <intel-pt.h>
-#include <memory>
#include "TraceCursorIntelPT.h"
-#include "lldb/Utility/StreamString.h"
+
+#include <memory>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::trace_intel_pt;
using namespace llvm;
+bool lldb_private::trace_intel_pt::IsLibiptError(int libipt_status) {
+ return libipt_status < 0;
+}
+
+bool lldb_private::trace_intel_pt::IsEndOfStream(int libipt_status) {
+ return libipt_status == -pte_eos;
+}
+
+bool lldb_private::trace_intel_pt::IsTscUnavailable(int libipt_status) {
+ return libipt_status == -pte_no_time;
+}
+
char IntelPTError::ID;
IntelPTError::IntelPTError(int libipt_error_code, lldb::addr_t address)
@@ -27,92 +39,167 @@ IntelPTError::IntelPTError(int libipt_error_code, lldb::addr_t address)
}
void IntelPTError::log(llvm::raw_ostream &OS) const {
- const char *libipt_error_message = pt_errstr(pt_errcode(m_libipt_error_code));
- if (m_address != LLDB_INVALID_ADDRESS && m_address > 0) {
- write_hex(OS, m_address, HexPrintStyle::PrefixLower, 18);
- OS << " ";
+ OS << pt_errstr(pt_errcode(m_libipt_error_code));
+ if (m_address != LLDB_INVALID_ADDRESS && m_address > 0)
+ OS << formatv(": {0:x+16}", m_address);
+}
+
+int64_t DecodedThread::GetItemsCount() const {
+ return static_cast<int64_t>(m_item_kinds.size());
+}
+
+lldb::addr_t DecodedThread::GetInstructionLoadAddress(size_t item_index) const {
+ return m_item_data[item_index].load_address;
+}
+
+ThreadSP DecodedThread::GetThread() { return m_thread_sp; }
+
+DecodedThread::TraceItemStorage &
+DecodedThread::CreateNewTraceItem(lldb::TraceItemKind kind) {
+ m_item_kinds.push_back(kind);
+ m_item_data.emplace_back();
+ return m_item_data.back();
+}
+
+void DecodedThread::NotifyTsc(uint64_t tsc) {
+ if (!m_last_tsc || *m_last_tsc != tsc) {
+ m_instruction_timestamps.emplace(m_item_kinds.size(), tsc);
+ m_last_tsc = tsc;
}
- OS << "error: " << libipt_error_message;
}
-IntelPTInstruction::IntelPTInstruction(llvm::Error err) {
- llvm::handleAllErrors(std::move(err),
- [&](std::unique_ptr<llvm::ErrorInfoBase> info) {
- m_error = std::move(info);
- });
- m_pt_insn.ip = LLDB_INVALID_ADDRESS;
- m_pt_insn.iclass = ptic_error;
+void DecodedThread::AppendEvent(lldb::TraceEvent event) {
+ CreateNewTraceItem(lldb::eTraceItemKindEvent).event = event;
+ m_events_stats.RecordEvent(event);
+}
+
+void DecodedThread::AppendInstruction(const pt_insn &insn) {
+ CreateNewTraceItem(lldb::eTraceItemKindInstruction).load_address = insn.ip;
+}
+
+void DecodedThread::AppendError(const IntelPTError &error) {
+ // End of stream shouldn't be a public error
+ if (IsEndOfStream(error.GetLibiptErrorCode()))
+ return;
+ CreateNewTraceItem(lldb::eTraceItemKindError).error =
+ ConstString(error.message()).AsCString();
}
-bool IntelPTInstruction::IsError() const { return (bool)m_error; }
+void DecodedThread::AppendCustomError(StringRef err) {
+ CreateNewTraceItem(lldb::eTraceItemKindError).error =
+ ConstString(err).AsCString();
+}
+
+lldb::TraceEvent DecodedThread::GetEventByIndex(int item_index) const {
+ return m_item_data[item_index].event;
+}
-lldb::addr_t IntelPTInstruction::GetLoadAddress() const { return m_pt_insn.ip; }
+void DecodedThread::LibiptErrorsStats::RecordError(int libipt_error_code) {
+ libipt_errors_counts[pt_errstr(pt_errcode(libipt_error_code))]++;
+ total_count++;
+}
-Optional<uint64_t> IntelPTInstruction::GetTimestampCounter() const {
- return m_timestamp;
+void DecodedThread::RecordTscError(int libipt_error_code) {
+ m_tsc_errors_stats.RecordError(libipt_error_code);
}
-Error IntelPTInstruction::ToError() const {
- if (!IsError())
- return Error::success();
+const DecodedThread::LibiptErrorsStats &
+DecodedThread::GetTscErrorsStats() const {
+ return m_tsc_errors_stats;
+}
- if (m_error->isA<IntelPTError>())
- return make_error<IntelPTError>(static_cast<IntelPTError &>(*m_error));
- return make_error<StringError>(m_error->message(),
- m_error->convertToErrorCode());
+const DecodedThread::EventsStats &DecodedThread::GetEventsStats() const {
+ return m_events_stats;
}
-size_t DecodedThread::GetRawTraceSize() const { return m_raw_trace_size; }
-TraceInstructionControlFlowType
-IntelPTInstruction::GetControlFlowType(lldb::addr_t next_load_address) const {
- if (IsError())
- return (TraceInstructionControlFlowType)0;
+void DecodedThread::EventsStats::RecordEvent(lldb::TraceEvent event) {
+ events_counts[event]++;
+ total_count++;
+}
- TraceInstructionControlFlowType mask =
- eTraceInstructionControlFlowTypeInstruction;
+Optional<DecodedThread::TscRange> DecodedThread::CalculateTscRange(
+ size_t insn_index,
+ const Optional<DecodedThread::TscRange> &hint_range) const {
+ // We first try to check the given hint range in case we are traversing the
+ // trace in short jumps. If that fails, then we do the more expensive
+ // arbitrary lookup.
+ if (hint_range) {
+ Optional<TscRange> candidate_range;
+ if (insn_index < hint_range->GetStartInstructionIndex())
+ candidate_range = hint_range->Prev();
+ else if (insn_index > hint_range->GetEndInstructionIndex())
+ candidate_range = hint_range->Next();
+ else
+ candidate_range = hint_range;
- switch (m_pt_insn.iclass) {
- case ptic_cond_jump:
- case ptic_jump:
- case ptic_far_jump:
- mask |= eTraceInstructionControlFlowTypeBranch;
- if (m_pt_insn.ip + m_pt_insn.size != next_load_address)
- mask |= eTraceInstructionControlFlowTypeTakenBranch;
- break;
- case ptic_return:
- case ptic_far_return:
- mask |= eTraceInstructionControlFlowTypeReturn;
- break;
- case ptic_call:
- case ptic_far_call:
- mask |= eTraceInstructionControlFlowTypeCall;
- break;
- default:
- break;
+ if (candidate_range && candidate_range->InRange(insn_index))
+ return candidate_range;
}
+ // Now we do a more expensive lookup
+ auto it = m_instruction_timestamps.upper_bound(insn_index);
+ if (it == m_instruction_timestamps.begin())
+ return None;
- return mask;
+ return TscRange(--it, *this);
}
-ArrayRef<IntelPTInstruction> DecodedThread::GetInstructions() const {
- return makeArrayRef(m_instructions);
+lldb::TraceItemKind DecodedThread::GetItemKindByIndex(size_t item_index) const {
+ return static_cast<lldb::TraceItemKind>(m_item_kinds[item_index]);
}
-DecodedThread::DecodedThread(ThreadSP thread_sp, Error error)
- : m_thread_sp(thread_sp) {
- m_instructions.emplace_back(std::move(error));
+const char *DecodedThread::GetErrorByIndex(size_t item_index) const {
+ return m_item_data[item_index].error;
}
-DecodedThread::DecodedThread(ThreadSP thread_sp,
- std::vector<IntelPTInstruction> &&instructions,
- size_t raw_trace_size)
- : m_thread_sp(thread_sp), m_instructions(std::move(instructions)),
- m_raw_trace_size(raw_trace_size) {
- if (m_instructions.empty())
- m_instructions.emplace_back(
- createStringError(inconvertibleErrorCode(), "empty trace"));
-}
+DecodedThread::DecodedThread(ThreadSP thread_sp) : m_thread_sp(thread_sp) {}
-lldb::TraceCursorUP DecodedThread::GetCursor() {
+lldb::TraceCursorUP DecodedThread::CreateNewCursor() {
return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this());
}
+
+size_t DecodedThread::CalculateApproximateMemoryUsage() const {
+ return sizeof(TraceItemStorage) * m_item_data.size() +
+ sizeof(uint8_t) * m_item_kinds.size() +
+ (sizeof(size_t) + sizeof(uint64_t)) * m_instruction_timestamps.size();
+}
+
+DecodedThread::TscRange::TscRange(std::map<size_t, uint64_t>::const_iterator it,
+ const DecodedThread &decoded_thread)
+ : m_it(it), m_decoded_thread(&decoded_thread) {
+ auto next_it = m_it;
+ ++next_it;
+ m_end_index = (next_it == m_decoded_thread->m_instruction_timestamps.end())
+ ? std::numeric_limits<uint64_t>::max()
+ : next_it->first - 1;
+}
+
+size_t DecodedThread::TscRange::GetTsc() const { return m_it->second; }
+
+size_t DecodedThread::TscRange::GetStartInstructionIndex() const {
+ return m_it->first;
+}
+
+size_t DecodedThread::TscRange::GetEndInstructionIndex() const {
+ return m_end_index;
+}
+
+bool DecodedThread::TscRange::InRange(size_t insn_index) const {
+ return GetStartInstructionIndex() <= insn_index &&
+ insn_index <= GetEndInstructionIndex();
+}
+
+Optional<DecodedThread::TscRange> DecodedThread::TscRange::Next() const {
+ auto next_it = m_it;
+ ++next_it;
+ if (next_it == m_decoded_thread->m_instruction_timestamps.end())
+ return None;
+ return TscRange(next_it, *m_decoded_thread);
+}
+
+Optional<DecodedThread::TscRange> DecodedThread::TscRange::Prev() const {
+ if (m_it == m_decoded_thread->m_instruction_timestamps.begin())
+ return None;
+ auto prev_it = m_it;
+ --prev_it;
+ return TscRange(prev_it, *m_decoded_thread);
+}