1753f127fSDimitry Andric //===-- TraceIntelPTMultiCpuDecoder.cpp -----------------------------------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #include "TraceIntelPTMultiCpuDecoder.h" 1081ad6265SDimitry Andric 1181ad6265SDimitry Andric #include "TraceIntelPT.h" 1281ad6265SDimitry Andric 1381ad6265SDimitry Andric #include "llvm/Support/Error.h" 1481ad6265SDimitry Andric 1581ad6265SDimitry Andric using namespace lldb; 1681ad6265SDimitry Andric using namespace lldb_private; 1781ad6265SDimitry Andric using namespace lldb_private::trace_intel_pt; 1881ad6265SDimitry Andric using namespace llvm; 1981ad6265SDimitry Andric 2081ad6265SDimitry Andric TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder( 2181ad6265SDimitry Andric TraceIntelPTSP trace_sp) 2281ad6265SDimitry Andric : m_trace_wp(trace_sp) { 2381ad6265SDimitry Andric for (Process *proc : trace_sp->GetAllProcesses()) { 2481ad6265SDimitry Andric for (ThreadSP thread_sp : proc->GetThreadList().Threads()) { 2581ad6265SDimitry Andric m_tids.insert(thread_sp->GetID()); 2681ad6265SDimitry Andric } 2781ad6265SDimitry Andric } 2881ad6265SDimitry Andric } 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric TraceIntelPTSP TraceIntelPTMultiCpuDecoder::GetTrace() { 3181ad6265SDimitry Andric return m_trace_wp.lock(); 3281ad6265SDimitry Andric } 3381ad6265SDimitry Andric 3481ad6265SDimitry Andric bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const { 3581ad6265SDimitry Andric return m_tids.count(tid); 3681ad6265SDimitry Andric } 3781ad6265SDimitry Andric 38*972a253aSDimitry Andric Expected<Optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() { 39*972a253aSDimitry Andric Optional<uint64_t> lowest_tsc; 40*972a253aSDimitry Andric TraceIntelPTSP trace_sp = GetTrace(); 41*972a253aSDimitry Andric 42*972a253aSDimitry Andric Error err = GetTrace()->OnAllCpusBinaryDataRead( 43*972a253aSDimitry Andric IntelPTDataKinds::kIptTrace, 44*972a253aSDimitry Andric [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error { 45*972a253aSDimitry Andric for (auto &cpu_id_to_buffer : buffers) { 46*972a253aSDimitry Andric Expected<Optional<uint64_t>> tsc = 47*972a253aSDimitry Andric FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second); 48*972a253aSDimitry Andric if (!tsc) 49*972a253aSDimitry Andric return tsc.takeError(); 50*972a253aSDimitry Andric if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc)) 51*972a253aSDimitry Andric lowest_tsc = **tsc; 52*972a253aSDimitry Andric } 53*972a253aSDimitry Andric return Error::success(); 54*972a253aSDimitry Andric }); 55*972a253aSDimitry Andric if (err) 56*972a253aSDimitry Andric return std::move(err); 57*972a253aSDimitry Andric return lowest_tsc; 58*972a253aSDimitry Andric } 59*972a253aSDimitry Andric 6081ad6265SDimitry Andric Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) { 6181ad6265SDimitry Andric if (Error err = CorrelateContextSwitchesAndIntelPtTraces()) 6281ad6265SDimitry Andric return std::move(err); 6381ad6265SDimitry Andric 64753f127fSDimitry Andric TraceIntelPTSP trace_sp = GetTrace(); 65753f127fSDimitry Andric 66753f127fSDimitry Andric return trace_sp 67753f127fSDimitry Andric ->GetThreadTimer(thread.GetID()) 68753f127fSDimitry Andric .TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> { 6981ad6265SDimitry Andric auto it = m_decoded_threads.find(thread.GetID()); 7081ad6265SDimitry Andric if (it != m_decoded_threads.end()) 7181ad6265SDimitry Andric return it->second; 7281ad6265SDimitry Andric 73*972a253aSDimitry Andric DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>( 74*972a253aSDimitry Andric thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion()); 7581ad6265SDimitry Andric 7681ad6265SDimitry Andric Error err = trace_sp->OnAllCpusBinaryDataRead( 7781ad6265SDimitry Andric IntelPTDataKinds::kIptTrace, 7881ad6265SDimitry Andric [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error { 79753f127fSDimitry Andric auto it = 80753f127fSDimitry Andric m_continuous_executions_per_thread->find(thread.GetID()); 8181ad6265SDimitry Andric if (it != m_continuous_executions_per_thread->end()) 82753f127fSDimitry Andric return DecodeSystemWideTraceForThread( 83753f127fSDimitry Andric *decoded_thread_sp, *trace_sp, buffers, it->second); 8481ad6265SDimitry Andric 8581ad6265SDimitry Andric return Error::success(); 8681ad6265SDimitry Andric }); 8781ad6265SDimitry Andric if (err) 8881ad6265SDimitry Andric return std::move(err); 8981ad6265SDimitry Andric 9081ad6265SDimitry Andric m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp); 9181ad6265SDimitry Andric return decoded_thread_sp; 92753f127fSDimitry Andric }); 9381ad6265SDimitry Andric } 9481ad6265SDimitry Andric 9581ad6265SDimitry Andric static Expected<std::vector<IntelPTThreadSubtrace>> 9681ad6265SDimitry Andric GetIntelPTSubtracesForCpu(TraceIntelPT &trace, cpu_id_t cpu_id) { 9781ad6265SDimitry Andric std::vector<IntelPTThreadSubtrace> intel_pt_subtraces; 9881ad6265SDimitry Andric Error err = trace.OnCpuBinaryDataRead( 9981ad6265SDimitry Andric cpu_id, IntelPTDataKinds::kIptTrace, 10081ad6265SDimitry Andric [&](ArrayRef<uint8_t> data) -> Error { 10181ad6265SDimitry Andric Expected<std::vector<IntelPTThreadSubtrace>> split_trace = 10281ad6265SDimitry Andric SplitTraceInContinuousExecutions(trace, data); 10381ad6265SDimitry Andric if (!split_trace) 10481ad6265SDimitry Andric return split_trace.takeError(); 10581ad6265SDimitry Andric 10681ad6265SDimitry Andric intel_pt_subtraces = std::move(*split_trace); 10781ad6265SDimitry Andric return Error::success(); 10881ad6265SDimitry Andric }); 10981ad6265SDimitry Andric if (err) 11081ad6265SDimitry Andric return std::move(err); 11181ad6265SDimitry Andric return intel_pt_subtraces; 11281ad6265SDimitry Andric } 11381ad6265SDimitry Andric 11481ad6265SDimitry Andric Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>> 11581ad6265SDimitry Andric TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() { 11681ad6265SDimitry Andric DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>> 11781ad6265SDimitry Andric continuous_executions_per_thread; 11881ad6265SDimitry Andric TraceIntelPTSP trace_sp = GetTrace(); 11981ad6265SDimitry Andric 12081ad6265SDimitry Andric Optional<LinuxPerfZeroTscConversion> conv_opt = 12181ad6265SDimitry Andric trace_sp->GetPerfZeroTscConversion(); 12281ad6265SDimitry Andric if (!conv_opt) 12381ad6265SDimitry Andric return createStringError( 12481ad6265SDimitry Andric inconvertibleErrorCode(), 12581ad6265SDimitry Andric "TSC to nanoseconds conversion values were not found"); 12681ad6265SDimitry Andric 12781ad6265SDimitry Andric LinuxPerfZeroTscConversion tsc_conversion = *conv_opt; 12881ad6265SDimitry Andric 12981ad6265SDimitry Andric for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) { 13081ad6265SDimitry Andric Expected<std::vector<IntelPTThreadSubtrace>> intel_pt_subtraces = 13181ad6265SDimitry Andric GetIntelPTSubtracesForCpu(*trace_sp, cpu_id); 13281ad6265SDimitry Andric if (!intel_pt_subtraces) 13381ad6265SDimitry Andric return intel_pt_subtraces.takeError(); 13481ad6265SDimitry Andric 135753f127fSDimitry Andric m_total_psb_blocks += intel_pt_subtraces->size(); 13681ad6265SDimitry Andric // We'll be iterating through the thread continuous executions and the intel 13781ad6265SDimitry Andric // pt subtraces sorted by time. 13881ad6265SDimitry Andric auto it = intel_pt_subtraces->begin(); 13981ad6265SDimitry Andric auto on_new_thread_execution = 14081ad6265SDimitry Andric [&](const ThreadContinuousExecution &thread_execution) { 14181ad6265SDimitry Andric IntelPTThreadContinousExecution execution(thread_execution); 14281ad6265SDimitry Andric 14381ad6265SDimitry Andric for (; it != intel_pt_subtraces->end() && 14481ad6265SDimitry Andric it->tsc < thread_execution.GetEndTSC(); 14581ad6265SDimitry Andric it++) { 14681ad6265SDimitry Andric if (it->tsc > thread_execution.GetStartTSC()) { 14781ad6265SDimitry Andric execution.intelpt_subtraces.push_back(*it); 14881ad6265SDimitry Andric } else { 149753f127fSDimitry Andric m_unattributed_psb_blocks++; 15081ad6265SDimitry Andric } 15181ad6265SDimitry Andric } 15281ad6265SDimitry Andric continuous_executions_per_thread[thread_execution.tid].push_back( 15381ad6265SDimitry Andric execution); 15481ad6265SDimitry Andric }; 15581ad6265SDimitry Andric Error err = trace_sp->OnCpuBinaryDataRead( 15681ad6265SDimitry Andric cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace, 15781ad6265SDimitry Andric [&](ArrayRef<uint8_t> data) -> Error { 15881ad6265SDimitry Andric Expected<std::vector<ThreadContinuousExecution>> executions = 15981ad6265SDimitry Andric DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion); 16081ad6265SDimitry Andric if (!executions) 16181ad6265SDimitry Andric return executions.takeError(); 16281ad6265SDimitry Andric for (const ThreadContinuousExecution &exec : *executions) 16381ad6265SDimitry Andric on_new_thread_execution(exec); 16481ad6265SDimitry Andric return Error::success(); 16581ad6265SDimitry Andric }); 16681ad6265SDimitry Andric if (err) 16781ad6265SDimitry Andric return std::move(err); 168753f127fSDimitry Andric 169753f127fSDimitry Andric m_unattributed_psb_blocks += intel_pt_subtraces->end() - it; 17081ad6265SDimitry Andric } 17181ad6265SDimitry Andric // We now sort the executions of each thread to have them ready for 17281ad6265SDimitry Andric // instruction decoding 17381ad6265SDimitry Andric for (auto &tid_executions : continuous_executions_per_thread) 17481ad6265SDimitry Andric std::sort(tid_executions.second.begin(), tid_executions.second.end()); 17581ad6265SDimitry Andric 17681ad6265SDimitry Andric return continuous_executions_per_thread; 17781ad6265SDimitry Andric } 17881ad6265SDimitry Andric 17981ad6265SDimitry Andric Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() { 18081ad6265SDimitry Andric if (m_setup_error) 18181ad6265SDimitry Andric return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 18281ad6265SDimitry Andric 18381ad6265SDimitry Andric if (m_continuous_executions_per_thread) 18481ad6265SDimitry Andric return Error::success(); 18581ad6265SDimitry Andric 186753f127fSDimitry Andric Error err = GetTrace()->GetGlobalTimer().TimeTask( 18781ad6265SDimitry Andric "Context switch and Intel PT traces correlation", [&]() -> Error { 18881ad6265SDimitry Andric if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) { 18981ad6265SDimitry Andric m_continuous_executions_per_thread.emplace(std::move(*correlation)); 19081ad6265SDimitry Andric return Error::success(); 19181ad6265SDimitry Andric } else { 19281ad6265SDimitry Andric return correlation.takeError(); 19381ad6265SDimitry Andric } 19481ad6265SDimitry Andric }); 19581ad6265SDimitry Andric if (err) { 19681ad6265SDimitry Andric m_setup_error = toString(std::move(err)); 19781ad6265SDimitry Andric return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 19881ad6265SDimitry Andric } 19981ad6265SDimitry Andric return Error::success(); 20081ad6265SDimitry Andric } 20181ad6265SDimitry Andric 20281ad6265SDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread( 20381ad6265SDimitry Andric lldb::tid_t tid) const { 20481ad6265SDimitry Andric if (!m_continuous_executions_per_thread) 20581ad6265SDimitry Andric return 0; 20681ad6265SDimitry Andric auto it = m_continuous_executions_per_thread->find(tid); 20781ad6265SDimitry Andric if (it == m_continuous_executions_per_thread->end()) 20881ad6265SDimitry Andric return 0; 20981ad6265SDimitry Andric return it->second.size(); 21081ad6265SDimitry Andric } 21181ad6265SDimitry Andric 21281ad6265SDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const { 21381ad6265SDimitry Andric if (!m_continuous_executions_per_thread) 21481ad6265SDimitry Andric return 0; 21581ad6265SDimitry Andric size_t count = 0; 21681ad6265SDimitry Andric for (const auto &kv : *m_continuous_executions_per_thread) 21781ad6265SDimitry Andric count += kv.second.size(); 21881ad6265SDimitry Andric return count; 21981ad6265SDimitry Andric } 220753f127fSDimitry Andric 221753f127fSDimitry Andric size_t 222753f127fSDimitry Andric TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const { 223753f127fSDimitry Andric if (!m_continuous_executions_per_thread) 224753f127fSDimitry Andric return 0; 225753f127fSDimitry Andric size_t count = 0; 226753f127fSDimitry Andric auto it = m_continuous_executions_per_thread->find(tid); 227753f127fSDimitry Andric if (it == m_continuous_executions_per_thread->end()) 228753f127fSDimitry Andric return 0; 229753f127fSDimitry Andric for (const IntelPTThreadContinousExecution &execution : it->second) 230753f127fSDimitry Andric count += execution.intelpt_subtraces.size(); 231753f127fSDimitry Andric return count; 232753f127fSDimitry Andric } 233753f127fSDimitry Andric 234753f127fSDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const { 235753f127fSDimitry Andric return m_unattributed_psb_blocks; 236753f127fSDimitry Andric } 237753f127fSDimitry Andric 238753f127fSDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const { 239753f127fSDimitry Andric return m_total_psb_blocks; 240753f127fSDimitry Andric } 241