Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp
39648 views
//===-- TraceIntelPTMultiCpuDecoder.cpp -----------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "TraceIntelPTMultiCpuDecoder.h"9#include "TraceIntelPT.h"10#include "llvm/Support/Error.h"11#include <optional>1213using namespace lldb;14using namespace lldb_private;15using namespace lldb_private::trace_intel_pt;16using namespace llvm;1718TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder(19TraceIntelPTSP trace_sp)20: m_trace_wp(trace_sp) {21for (Process *proc : trace_sp->GetAllProcesses()) {22for (ThreadSP thread_sp : proc->GetThreadList().Threads()) {23m_tids.insert(thread_sp->GetID());24}25}26}2728TraceIntelPTSP TraceIntelPTMultiCpuDecoder::GetTrace() {29return m_trace_wp.lock();30}3132bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const {33return m_tids.count(tid);34}3536Expected<std::optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() {37std::optional<uint64_t> lowest_tsc;38TraceIntelPTSP trace_sp = GetTrace();3940Error err = GetTrace()->OnAllCpusBinaryDataRead(41IntelPTDataKinds::kIptTrace,42[&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {43for (auto &cpu_id_to_buffer : buffers) {44Expected<std::optional<uint64_t>> tsc =45FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second);46if (!tsc)47return tsc.takeError();48if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))49lowest_tsc = **tsc;50}51return Error::success();52});53if (err)54return std::move(err);55return lowest_tsc;56}5758Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {59if (Error err = CorrelateContextSwitchesAndIntelPtTraces())60return std::move(err);6162TraceIntelPTSP trace_sp = GetTrace();6364return trace_sp->GetThreadTimer(thread.GetID())65.TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> {66auto it = m_decoded_threads.find(thread.GetID());67if (it != m_decoded_threads.end())68return it->second;6970DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(71thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion());7273Error err = trace_sp->OnAllCpusBinaryDataRead(74IntelPTDataKinds::kIptTrace,75[&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {76auto it =77m_continuous_executions_per_thread->find(thread.GetID());78if (it != m_continuous_executions_per_thread->end())79return DecodeSystemWideTraceForThread(80*decoded_thread_sp, *trace_sp, buffers, it->second);8182return Error::success();83});84if (err)85return std::move(err);8687m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp);88return decoded_thread_sp;89});90}9192static Expected<std::vector<PSBBlock>> GetPSBBlocksForCPU(TraceIntelPT &trace,93cpu_id_t cpu_id) {94std::vector<PSBBlock> psb_blocks;95Error err = trace.OnCpuBinaryDataRead(96cpu_id, IntelPTDataKinds::kIptTrace,97[&](ArrayRef<uint8_t> data) -> Error {98Expected<std::vector<PSBBlock>> split_trace =99SplitTraceIntoPSBBlock(trace, data, /*expect_tscs=*/true);100if (!split_trace)101return split_trace.takeError();102103psb_blocks = std::move(*split_trace);104return Error::success();105});106if (err)107return std::move(err);108return psb_blocks;109}110111Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>112TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {113DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>114continuous_executions_per_thread;115TraceIntelPTSP trace_sp = GetTrace();116117std::optional<LinuxPerfZeroTscConversion> conv_opt =118trace_sp->GetPerfZeroTscConversion();119if (!conv_opt)120return createStringError(121inconvertibleErrorCode(),122"TSC to nanoseconds conversion values were not found");123124LinuxPerfZeroTscConversion tsc_conversion = *conv_opt;125126for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) {127Expected<std::vector<PSBBlock>> psb_blocks =128GetPSBBlocksForCPU(*trace_sp, cpu_id);129if (!psb_blocks)130return psb_blocks.takeError();131132m_total_psb_blocks += psb_blocks->size();133// We'll be iterating through the thread continuous executions and the intel134// pt subtraces sorted by time.135auto it = psb_blocks->begin();136auto on_new_thread_execution =137[&](const ThreadContinuousExecution &thread_execution) {138IntelPTThreadContinousExecution execution(thread_execution);139140for (; it != psb_blocks->end() &&141*it->tsc < thread_execution.GetEndTSC();142it++) {143if (*it->tsc > thread_execution.GetStartTSC()) {144execution.psb_blocks.push_back(*it);145} else {146m_unattributed_psb_blocks++;147}148}149continuous_executions_per_thread[thread_execution.tid].push_back(150execution);151};152Error err = trace_sp->OnCpuBinaryDataRead(153cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,154[&](ArrayRef<uint8_t> data) -> Error {155Expected<std::vector<ThreadContinuousExecution>> executions =156DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion);157if (!executions)158return executions.takeError();159for (const ThreadContinuousExecution &exec : *executions)160on_new_thread_execution(exec);161return Error::success();162});163if (err)164return std::move(err);165166m_unattributed_psb_blocks += psb_blocks->end() - it;167}168// We now sort the executions of each thread to have them ready for169// instruction decoding170for (auto &tid_executions : continuous_executions_per_thread)171std::sort(tid_executions.second.begin(), tid_executions.second.end());172173return continuous_executions_per_thread;174}175176Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() {177if (m_setup_error)178return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());179180if (m_continuous_executions_per_thread)181return Error::success();182183Error err = GetTrace()->GetGlobalTimer().TimeTask(184"Context switch and Intel PT traces correlation", [&]() -> Error {185if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) {186m_continuous_executions_per_thread.emplace(std::move(*correlation));187return Error::success();188} else {189return correlation.takeError();190}191});192if (err) {193m_setup_error = toString(std::move(err));194return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());195}196return Error::success();197}198199size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread(200lldb::tid_t tid) const {201if (!m_continuous_executions_per_thread)202return 0;203auto it = m_continuous_executions_per_thread->find(tid);204if (it == m_continuous_executions_per_thread->end())205return 0;206return it->second.size();207}208209size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const {210if (!m_continuous_executions_per_thread)211return 0;212size_t count = 0;213for (const auto &kv : *m_continuous_executions_per_thread)214count += kv.second.size();215return count;216}217218size_t219TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const {220if (!m_continuous_executions_per_thread)221return 0;222size_t count = 0;223auto it = m_continuous_executions_per_thread->find(tid);224if (it == m_continuous_executions_per_thread->end())225return 0;226for (const IntelPTThreadContinousExecution &execution : it->second)227count += execution.psb_blocks.size();228return count;229}230231size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const {232return m_unattributed_psb_blocks;233}234235size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const {236return m_total_psb_blocks;237}238239240