diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp new file mode 100644 index 000000000000..e2ca8b4d1db0 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp @@ -0,0 +1,238 @@ +//===-- TraceIntelPTMultiCpuDecoder.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 "TraceIntelPTMultiCpuDecoder.h" +#include "TraceIntelPT.h" +#include "llvm/Support/Error.h" +#include <optional> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder( + TraceIntelPTSP trace_sp) + : m_trace_wp(trace_sp) { + for (Process *proc : trace_sp->GetAllProcesses()) { + for (ThreadSP thread_sp : proc->GetThreadList().Threads()) { + m_tids.insert(thread_sp->GetID()); + } + } +} + +TraceIntelPTSP TraceIntelPTMultiCpuDecoder::GetTrace() { + return m_trace_wp.lock(); +} + +bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const { + return m_tids.count(tid); +} + +Expected<std::optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() { + std::optional<uint64_t> lowest_tsc; + TraceIntelPTSP trace_sp = GetTrace(); + + Error err = GetTrace()->OnAllCpusBinaryDataRead( + IntelPTDataKinds::kIptTrace, + [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error { + for (auto &cpu_id_to_buffer : buffers) { + Expected<std::optional<uint64_t>> tsc = + FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second); + if (!tsc) + return tsc.takeError(); + if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc)) + lowest_tsc = **tsc; + } + return Error::success(); + }); + if (err) + return std::move(err); + return lowest_tsc; +} + +Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) { + if (Error err = CorrelateContextSwitchesAndIntelPtTraces()) + return std::move(err); + + TraceIntelPTSP trace_sp = GetTrace(); + + return trace_sp->GetThreadTimer(thread.GetID()) + .TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> { + auto it = m_decoded_threads.find(thread.GetID()); + if (it != m_decoded_threads.end()) + return it->second; + + DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>( + thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion()); + + Error err = trace_sp->OnAllCpusBinaryDataRead( + IntelPTDataKinds::kIptTrace, + [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error { + auto it = + m_continuous_executions_per_thread->find(thread.GetID()); + if (it != m_continuous_executions_per_thread->end()) + return DecodeSystemWideTraceForThread( + *decoded_thread_sp, *trace_sp, buffers, it->second); + + return Error::success(); + }); + if (err) + return std::move(err); + + m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp); + return decoded_thread_sp; + }); +} + +static Expected<std::vector<PSBBlock>> GetPSBBlocksForCPU(TraceIntelPT &trace, + cpu_id_t cpu_id) { + std::vector<PSBBlock> psb_blocks; + Error err = trace.OnCpuBinaryDataRead( + cpu_id, IntelPTDataKinds::kIptTrace, + [&](ArrayRef<uint8_t> data) -> Error { + Expected<std::vector<PSBBlock>> split_trace = + SplitTraceIntoPSBBlock(trace, data, /*expect_tscs=*/true); + if (!split_trace) + return split_trace.takeError(); + + psb_blocks = std::move(*split_trace); + return Error::success(); + }); + if (err) + return std::move(err); + return psb_blocks; +} + +Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>> +TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() { + DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>> + continuous_executions_per_thread; + TraceIntelPTSP trace_sp = GetTrace(); + + std::optional<LinuxPerfZeroTscConversion> conv_opt = + trace_sp->GetPerfZeroTscConversion(); + if (!conv_opt) + return createStringError( + inconvertibleErrorCode(), + "TSC to nanoseconds conversion values were not found"); + + LinuxPerfZeroTscConversion tsc_conversion = *conv_opt; + + for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) { + Expected<std::vector<PSBBlock>> psb_blocks = + GetPSBBlocksForCPU(*trace_sp, cpu_id); + if (!psb_blocks) + return psb_blocks.takeError(); + + m_total_psb_blocks += psb_blocks->size(); + // We'll be iterating through the thread continuous executions and the intel + // pt subtraces sorted by time. + auto it = psb_blocks->begin(); + auto on_new_thread_execution = + [&](const ThreadContinuousExecution &thread_execution) { + IntelPTThreadContinousExecution execution(thread_execution); + + for (; it != psb_blocks->end() && + *it->tsc < thread_execution.GetEndTSC(); + it++) { + if (*it->tsc > thread_execution.GetStartTSC()) { + execution.psb_blocks.push_back(*it); + } else { + m_unattributed_psb_blocks++; + } + } + continuous_executions_per_thread[thread_execution.tid].push_back( + execution); + }; + Error err = trace_sp->OnCpuBinaryDataRead( + cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace, + [&](ArrayRef<uint8_t> data) -> Error { + Expected<std::vector<ThreadContinuousExecution>> executions = + DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion); + if (!executions) + return executions.takeError(); + for (const ThreadContinuousExecution &exec : *executions) + on_new_thread_execution(exec); + return Error::success(); + }); + if (err) + return std::move(err); + + m_unattributed_psb_blocks += psb_blocks->end() - it; + } + // We now sort the executions of each thread to have them ready for + // instruction decoding + for (auto &tid_executions : continuous_executions_per_thread) + std::sort(tid_executions.second.begin(), tid_executions.second.end()); + + return continuous_executions_per_thread; +} + +Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() { + if (m_setup_error) + return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); + + if (m_continuous_executions_per_thread) + return Error::success(); + + Error err = GetTrace()->GetGlobalTimer().TimeTask( + "Context switch and Intel PT traces correlation", [&]() -> Error { + if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) { + m_continuous_executions_per_thread.emplace(std::move(*correlation)); + return Error::success(); + } else { + return correlation.takeError(); + } + }); + if (err) { + m_setup_error = toString(std::move(err)); + return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); + } + return Error::success(); +} + +size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread( + lldb::tid_t tid) const { + if (!m_continuous_executions_per_thread) + return 0; + auto it = m_continuous_executions_per_thread->find(tid); + if (it == m_continuous_executions_per_thread->end()) + return 0; + return it->second.size(); +} + +size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const { + if (!m_continuous_executions_per_thread) + return 0; + size_t count = 0; + for (const auto &kv : *m_continuous_executions_per_thread) + count += kv.second.size(); + return count; +} + +size_t +TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const { + if (!m_continuous_executions_per_thread) + return 0; + size_t count = 0; + auto it = m_continuous_executions_per_thread->find(tid); + if (it == m_continuous_executions_per_thread->end()) + return 0; + for (const IntelPTThreadContinousExecution &execution : it->second) + count += execution.psb_blocks.size(); + return count; +} + +size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const { + return m_unattributed_psb_blocks; +} + +size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const { + return m_total_psb_blocks; +} |