diff --git a/lldb/source/Plugins/Process/Linux/Perf.cpp b/lldb/source/Plugins/Process/Linux/Perf.cpp --- a/lldb/source/Plugins/Process/Linux/Perf.cpp +++ b/lldb/source/Plugins/Process/Linux/Perf.cpp @@ -205,15 +205,13 @@ if (data_head > data_size) { uint64_t actual_data_head = data_head % data_size; - // The buffer has wrapped - for (uint64_t i = actual_data_head; i < data_size; i++) - output.push_back(data[i]); - - for (uint64_t i = 0; i < actual_data_head; i++) - output.push_back(data[i]); + // The buffer has wrapped, so we first the oldest chunk of data + output.insert(output.end(), data.begin() + actual_data_head, data.end()); + // And we we read the most recent chunk of data + output.insert(output.end(), data.begin(), data.begin() + actual_data_head); } else { - for (uint64_t i = 0; i < data_head; i++) - output.push_back(data[i]); + // There's been no wrapping, so we just read linearly + output.insert(output.end(), data.begin(), data.begin() + data_head); } if (was_enabled) { @@ -238,7 +236,6 @@ ArrayRef data = GetAuxBuffer(); uint64_t aux_head = mmap_metadata.aux_head; - uint64_t aux_size = mmap_metadata.aux_size; std::vector output; output.reserve(data.size()); @@ -254,11 +251,8 @@ * * */ - for (uint64_t i = aux_head; i < aux_size; i++) - output.push_back(data[i]); - - for (uint64_t i = 0; i < aux_head; i++) - output.push_back(data[i]); + output.insert(output.end(), data.begin() + aux_head, data.end()); + output.insert(output.end(), data.begin(), data.begin() + aux_head); if (was_enabled) { if (Error err = EnableWithIoctl()) diff --git a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h --- a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h +++ b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h @@ -48,21 +48,24 @@ void DecodeSingleTraceForThread(DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt, llvm::ArrayRef buffer); -/// Decode a raw Intel PT trace for a single thread that was collected in a per cpu core basis. +/// Decode a raw Intel PT trace for a single thread that was collected in a per +/// cpu core basis. /// -/// \param[in] decoded_thread -/// All decoded instructions, errors and events will be appended to this object. +/// \param[out] decoded_thread +/// All decoded instructions, errors and events will be appended to this +/// object. /// /// \param[in] trace_intel_pt -/// The main Trace object that contains all the information related to the trace session. +/// The main Trace object that contains all the information related to the +/// trace session. /// /// \param[in] buffers /// A map from cpu core id to raw intel pt buffers. /// /// \param[in] executions -/// A list of chunks of timed executions of the same given thread. It is used to identify if -/// some executions have missing intel pt data and also to determine in which core a certain -/// part of the execution ocurred. +/// A list of chunks of timed executions of the same given thread. It is used +/// to identify if some executions have missing intel pt data and also to +/// determine in which core a certain part of the execution ocurred. void DecodeSystemWideTraceForThread( DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt, const llvm::DenseMap> &buffers, diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h @@ -37,7 +37,7 @@ static void Terminate(); - /// Create an instance of this class. + /// Create an instance of this class from a trace bundle. /// /// \param[in] trace_session_file /// The contents of the trace session file. See \a Trace::FindPlugin. @@ -158,6 +158,8 @@ /// The timer object for this trace. TaskTimer &GetTimer(); + TraceIntelPTSP GetSharedPtr(); + private: friend class TraceIntelPTSessionFileParser; @@ -174,9 +176,20 @@ /// \param[in] trace_threads /// The threads traced in the live session. They must belong to the /// processes mentioned above. + /// + /// \return + /// A TraceIntelPT shared pointer instance. + /// \{ + static TraceIntelPTSP CreateInstanceForPostmortemTrace( + JSONTraceSession &session, + llvm::ArrayRef traced_processes, + llvm::ArrayRef traced_threads); + + /// This constructor is used by CreateInstanceForPostmortemTrace to get the + /// instance ready before using shared pointers, which is a limitation of C++. TraceIntelPT(JSONTraceSession &session, - llvm::ArrayRef traced_processes, - llvm::ArrayRef traced_threads); + llvm::ArrayRef traced_processes); + /// \} /// Constructor for live processes TraceIntelPT(Process &live_process) : Trace(live_process){}; diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp @@ -74,23 +74,26 @@ return instance; } -TraceIntelPT::TraceIntelPT(JSONTraceSession &session, - ArrayRef traced_processes, - ArrayRef traced_threads) - : Trace(traced_processes, session.GetCpuIds()), - m_cpu_info(session.cpu_info) { - m_storage.tsc_conversion = session.tsc_perf_zero_conversion; +TraceIntelPTSP TraceIntelPT::GetSharedPtr() { + return std::static_pointer_cast(shared_from_this()); +} + +TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace( + JSONTraceSession &session, ArrayRef traced_processes, + ArrayRef traced_threads) { + TraceIntelPTSP trace_sp(new TraceIntelPT(session, traced_processes)); + trace_sp->m_storage.tsc_conversion = session.tsc_perf_zero_conversion; if (session.cpus) { std::vector cpus; for (const JSONCpu &cpu : *session.cpus) { - SetPostMortemCpuDataFile(cpu.id, IntelPTDataKinds::kIptTrace, - FileSpec(cpu.ipt_trace)); + trace_sp->SetPostMortemCpuDataFile(cpu.id, IntelPTDataKinds::kIptTrace, + FileSpec(cpu.ipt_trace)); - SetPostMortemCpuDataFile(cpu.id, - IntelPTDataKinds::kPerfContextSwitchTrace, - FileSpec(cpu.context_switch_trace)); + trace_sp->SetPostMortemCpuDataFile( + cpu.id, IntelPTDataKinds::kPerfContextSwitchTrace, + FileSpec(cpu.context_switch_trace)); cpus.push_back(cpu.id); } @@ -99,19 +102,28 @@ for (const JSONThread &thread : process.threads) tids.push_back(thread.tid); - m_storage.multicpu_decoder.emplace(*this); + trace_sp->m_storage.multicpu_decoder.emplace(trace_sp); } else { for (const ThreadPostMortemTraceSP &thread : traced_threads) { - m_storage.thread_decoders.try_emplace( - thread->GetID(), std::make_unique(thread, *this)); + trace_sp->m_storage.thread_decoders.try_emplace( + thread->GetID(), std::make_unique(thread, *trace_sp)); if (const Optional &trace_file = thread->GetTraceFile()) { - SetPostMortemThreadDataFile(thread->GetID(), - IntelPTDataKinds::kIptTrace, *trace_file); + trace_sp->SetPostMortemThreadDataFile( + thread->GetID(), IntelPTDataKinds::kIptTrace, *trace_file); } } } + + for (const ProcessSP &process_sp : traced_processes) + process_sp->GetTarget().SetTrace(trace_sp); + return trace_sp; } +TraceIntelPT::TraceIntelPT(JSONTraceSession &session, + ArrayRef traced_processes) + : Trace(traced_processes, session.GetCpuIds()), + m_cpu_info(session.cpu_info) {} + DecodedThreadSP TraceIntelPT::Decode(Thread &thread) { if (const char *error = RefreshLiveProcessState()) return std::make_shared( @@ -351,7 +363,7 @@ if (!intelpt_state->tsc_perf_zero_conversion) return createStringError(inconvertibleErrorCode(), "Missing perf time_zero conversion values"); - m_storage.multicpu_decoder.emplace(*this); + m_storage.multicpu_decoder.emplace(GetSharedPtr()); } if (m_storage.tsc_conversion) { diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h @@ -12,6 +12,7 @@ #include "LibiptDecoder.h" #include "PerfContextSwitchDecoder.h" #include "ThreadDecoder.h" +#include "forward-declarations.h" namespace lldb_private { namespace trace_intel_pt { @@ -31,7 +32,7 @@ public: /// \param[in] TraceIntelPT /// The trace object to be decoded - TraceIntelPTMultiCpuDecoder(TraceIntelPT &trace); + TraceIntelPTMultiCpuDecoder(TraceIntelPTSP trace_sp); /// \return /// A \a DecodedThread for the \p thread by decoding its instructions on all @@ -67,7 +68,9 @@ llvm::DenseMap>> DoCorrelateContextSwitchesAndIntelPtTraces(); - TraceIntelPT *m_trace; + TraceIntelPTSP GetTrace(); + + std::weak_ptr m_trace_wp; std::set m_tids; llvm::Optional< llvm::DenseMap>> diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp @@ -17,15 +17,20 @@ using namespace lldb_private::trace_intel_pt; using namespace llvm; -TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder(TraceIntelPT &trace) - : m_trace(&trace) { - for (Process *proc : trace.GetAllProcesses()) { +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); } @@ -41,12 +46,14 @@ DecodedThreadSP decoded_thread_sp = std::make_shared(thread.shared_from_this()); - Error err = m_trace->OnAllCpusBinaryDataRead( + TraceIntelPTSP trace_sp = GetTrace(); + + Error err = trace_sp->OnAllCpusBinaryDataRead( IntelPTDataKinds::kIptTrace, [&](const DenseMap> &buffers) -> Error { auto it = m_continuous_executions_per_thread->find(thread.GetID()); if (it != m_continuous_executions_per_thread->end()) - DecodeSystemWideTraceForThread(*decoded_thread_sp, *m_trace, buffers, + DecodeSystemWideTraceForThread(*decoded_thread_sp, *trace_sp, buffers, it->second); return Error::success(); @@ -81,9 +88,10 @@ TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() { DenseMap> continuous_executions_per_thread; + TraceIntelPTSP trace_sp = GetTrace(); Optional conv_opt = - m_trace->GetPerfZeroTscConversion(); + trace_sp->GetPerfZeroTscConversion(); if (!conv_opt) return createStringError( inconvertibleErrorCode(), @@ -91,9 +99,9 @@ LinuxPerfZeroTscConversion tsc_conversion = *conv_opt; - for (cpu_id_t cpu_id : m_trace->GetTracedCpus()) { + for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) { Expected> intel_pt_subtraces = - GetIntelPTSubtracesForCpu(*m_trace, cpu_id); + GetIntelPTSubtracesForCpu(*trace_sp, cpu_id); if (!intel_pt_subtraces) return intel_pt_subtraces.takeError(); @@ -116,7 +124,7 @@ continuous_executions_per_thread[thread_execution.tid].push_back( execution); }; - Error err = m_trace->OnCpuBinaryDataRead( + Error err = trace_sp->OnCpuBinaryDataRead( cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace, [&](ArrayRef data) -> Error { Expected> executions = @@ -145,7 +153,7 @@ if (m_continuous_executions_per_thread) return Error::success(); - Error err = m_trace->GetTimer().ForGlobal().TimeTask( + Error err = GetTrace()->GetTimer().ForGlobal().TimeTask( "Context switch and Intel PT traces correlation", [&]() -> Error { if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) { m_continuous_executions_per_thread.emplace(std::move(*correlation)); diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp @@ -284,7 +284,8 @@ parsed_process.threads.end()); } - TraceSP trace_instance(new TraceIntelPT(session, processes, threads)); + TraceSP trace_instance = TraceIntelPT::CreateInstanceForPostmortemTrace( + session, processes, threads); for (const ParsedProcess &parsed_process : parsed_processes) parsed_process.target_sp->SetTrace(trace_instance); diff --git a/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h b/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h --- a/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h +++ b/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h @@ -9,12 +9,16 @@ #ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H +#include + namespace lldb_private { namespace trace_intel_pt { class TraceIntelPT; class ThreadDecoder; +using TraceIntelPTSP = std::shared_ptr; + } // namespace trace_intel_pt } // namespace lldb_private #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H diff --git a/lldb/source/Target/Trace.cpp b/lldb/source/Target/Trace.cpp --- a/lldb/source/Target/Trace.cpp +++ b/lldb/source/Target/Trace.cpp @@ -63,16 +63,18 @@ return &it->second; } +/// Similar to the methods above but it looks for an item in a map of maps. template -static Optional Lookup2(DenseMap> &map, K1 k1, K2 k2) { +static Optional Lookup(DenseMap> &map, K1 k1, K2 k2) { auto it = map.find(k1); if (it == map.end()) return None; return Lookup(it->second, k2); } +/// Similar to the methods above but it looks for an item in a map of maps. template -static V *Lookup2AsPtr(DenseMap> &map, K1 k1, K2 k2) { +static V *LookupAsPtr(DenseMap> &map, K1 k1, K2 k2) { auto it = map.find(k1); if (it == map.end()) return nullptr; @@ -159,13 +161,13 @@ Optional Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid, llvm::StringRef kind) { Storage &storage = GetUpdatedStorage(); - return Lookup2(storage.live_thread_data, tid, ConstString(kind)); + return Lookup(storage.live_thread_data, tid, ConstString(kind)); } Optional Trace::GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id, llvm::StringRef kind) { Storage &storage = GetUpdatedStorage(); - return Lookup2(storage.live_cpu_data_sizes, cpu_id, ConstString(kind)); + return Lookup(storage.live_cpu_data_sizes, cpu_id, ConstString(kind)); } Optional Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) { @@ -345,7 +347,7 @@ Trace::GetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind) { Storage &storage = GetUpdatedStorage(); if (Optional file = - Lookup2(storage.postmortem_thread_data, tid, ConstString(kind))) + Lookup(storage.postmortem_thread_data, tid, ConstString(kind))) return *file; else return createStringError( @@ -358,7 +360,7 @@ llvm::StringRef kind) { Storage &storage = GetUpdatedStorage(); if (Optional file = - Lookup2(storage.postmortem_cpu_data, cpu_id, ConstString(kind))) + Lookup(storage.postmortem_cpu_data, cpu_id, ConstString(kind))) return *file; else return createStringError( @@ -393,7 +395,7 @@ OnBinaryDataReadCallback callback) { Storage &storage = GetUpdatedStorage(); if (std::vector *cpu_data = - Lookup2AsPtr(storage.live_cpu_data, cpu_id, ConstString(kind))) + LookupAsPtr(storage.live_cpu_data, cpu_id, ConstString(kind))) return callback(*cpu_data); Expected> data = GetLiveCpuBinaryData(cpu_id, kind);