diff options
Diffstat (limited to 'lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp')
| -rw-r--r-- | lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp | 219 |
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); +} |
