1*6a5355e8SWalter Erquinigo //===-- TraceIntelPTMultiCpuDecoder.cpp ----0------------------------------===// 2*6a5355e8SWalter Erquinigo // 3*6a5355e8SWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*6a5355e8SWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information. 5*6a5355e8SWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*6a5355e8SWalter Erquinigo // 7*6a5355e8SWalter Erquinigo //===----------------------------------------------------------------------===// 8*6a5355e8SWalter Erquinigo 9*6a5355e8SWalter Erquinigo #include "TraceIntelPTMultiCpuDecoder.h" 10*6a5355e8SWalter Erquinigo 11*6a5355e8SWalter Erquinigo #include "TraceIntelPT.h" 12*6a5355e8SWalter Erquinigo 13*6a5355e8SWalter Erquinigo #include "llvm/Support/Error.h" 14*6a5355e8SWalter Erquinigo 15*6a5355e8SWalter Erquinigo using namespace lldb; 16*6a5355e8SWalter Erquinigo using namespace lldb_private; 17*6a5355e8SWalter Erquinigo using namespace lldb_private::trace_intel_pt; 18*6a5355e8SWalter Erquinigo using namespace llvm; 19*6a5355e8SWalter Erquinigo 20*6a5355e8SWalter Erquinigo TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder(TraceIntelPT &trace) 21*6a5355e8SWalter Erquinigo : m_trace(&trace) { 22*6a5355e8SWalter Erquinigo for (Process *proc : trace.GetAllProcesses()) { 23*6a5355e8SWalter Erquinigo for (ThreadSP thread_sp : proc->GetThreadList().Threads()) { 24*6a5355e8SWalter Erquinigo m_tids.insert(thread_sp->GetID()); 25*6a5355e8SWalter Erquinigo } 26*6a5355e8SWalter Erquinigo } 27*6a5355e8SWalter Erquinigo } 28*6a5355e8SWalter Erquinigo 29*6a5355e8SWalter Erquinigo bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const { 30*6a5355e8SWalter Erquinigo return m_tids.count(tid); 31*6a5355e8SWalter Erquinigo } 32*6a5355e8SWalter Erquinigo 33*6a5355e8SWalter Erquinigo DecodedThreadSP TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) { 34*6a5355e8SWalter Erquinigo if (Error err = CorrelateContextSwitchesAndIntelPtTraces()) 35*6a5355e8SWalter Erquinigo return std::make_shared<DecodedThread>(thread.shared_from_this(), 36*6a5355e8SWalter Erquinigo std::move(err)); 37*6a5355e8SWalter Erquinigo auto it = m_decoded_threads.find(thread.GetID()); 38*6a5355e8SWalter Erquinigo if (it != m_decoded_threads.end()) 39*6a5355e8SWalter Erquinigo return it->second; 40*6a5355e8SWalter Erquinigo 41*6a5355e8SWalter Erquinigo DecodedThreadSP decoded_thread_sp = 42*6a5355e8SWalter Erquinigo std::make_shared<DecodedThread>(thread.shared_from_this()); 43*6a5355e8SWalter Erquinigo 44*6a5355e8SWalter Erquinigo Error err = m_trace->OnAllCpusBinaryDataRead( 45*6a5355e8SWalter Erquinigo IntelPTDataKinds::kIptTrace, 46*6a5355e8SWalter Erquinigo [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error { 47*6a5355e8SWalter Erquinigo auto it = m_continuous_executions_per_thread->find(thread.GetID()); 48*6a5355e8SWalter Erquinigo if (it != m_continuous_executions_per_thread->end()) 49*6a5355e8SWalter Erquinigo DecodeSystemWideTraceForThread(*decoded_thread_sp, *m_trace, buffers, 50*6a5355e8SWalter Erquinigo it->second); 51*6a5355e8SWalter Erquinigo 52*6a5355e8SWalter Erquinigo return Error::success(); 53*6a5355e8SWalter Erquinigo }); 54*6a5355e8SWalter Erquinigo if (err) 55*6a5355e8SWalter Erquinigo decoded_thread_sp->SetAsFailed(std::move(err)); 56*6a5355e8SWalter Erquinigo 57*6a5355e8SWalter Erquinigo m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp); 58*6a5355e8SWalter Erquinigo return decoded_thread_sp; 59*6a5355e8SWalter Erquinigo } 60*6a5355e8SWalter Erquinigo 61*6a5355e8SWalter Erquinigo static Expected<std::vector<IntelPTThreadSubtrace>> 62*6a5355e8SWalter Erquinigo GetIntelPTSubtracesForCpu(TraceIntelPT &trace, cpu_id_t cpu_id) { 63*6a5355e8SWalter Erquinigo std::vector<IntelPTThreadSubtrace> intel_pt_subtraces; 64*6a5355e8SWalter Erquinigo Error err = trace.OnCpuBinaryDataRead( 65*6a5355e8SWalter Erquinigo cpu_id, IntelPTDataKinds::kIptTrace, 66*6a5355e8SWalter Erquinigo [&](ArrayRef<uint8_t> data) -> Error { 67*6a5355e8SWalter Erquinigo Expected<std::vector<IntelPTThreadSubtrace>> split_trace = 68*6a5355e8SWalter Erquinigo SplitTraceInContinuousExecutions(trace, data); 69*6a5355e8SWalter Erquinigo if (!split_trace) 70*6a5355e8SWalter Erquinigo return split_trace.takeError(); 71*6a5355e8SWalter Erquinigo 72*6a5355e8SWalter Erquinigo intel_pt_subtraces = std::move(*split_trace); 73*6a5355e8SWalter Erquinigo return Error::success(); 74*6a5355e8SWalter Erquinigo }); 75*6a5355e8SWalter Erquinigo if (err) 76*6a5355e8SWalter Erquinigo return std::move(err); 77*6a5355e8SWalter Erquinigo return intel_pt_subtraces; 78*6a5355e8SWalter Erquinigo } 79*6a5355e8SWalter Erquinigo 80*6a5355e8SWalter Erquinigo Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>> 81*6a5355e8SWalter Erquinigo TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() { 82*6a5355e8SWalter Erquinigo DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>> 83*6a5355e8SWalter Erquinigo continuous_executions_per_thread; 84*6a5355e8SWalter Erquinigo 85*6a5355e8SWalter Erquinigo Optional<LinuxPerfZeroTscConversion> conv_opt = 86*6a5355e8SWalter Erquinigo m_trace->GetPerfZeroTscConversion(); 87*6a5355e8SWalter Erquinigo if (!conv_opt) 88*6a5355e8SWalter Erquinigo return createStringError( 89*6a5355e8SWalter Erquinigo inconvertibleErrorCode(), 90*6a5355e8SWalter Erquinigo "TSC to nanoseconds conversion values were not found"); 91*6a5355e8SWalter Erquinigo 92*6a5355e8SWalter Erquinigo LinuxPerfZeroTscConversion tsc_conversion = *conv_opt; 93*6a5355e8SWalter Erquinigo 94*6a5355e8SWalter Erquinigo for (cpu_id_t cpu_id : m_trace->GetTracedCpus()) { 95*6a5355e8SWalter Erquinigo Expected<std::vector<IntelPTThreadSubtrace>> intel_pt_subtraces = 96*6a5355e8SWalter Erquinigo GetIntelPTSubtracesForCpu(*m_trace, cpu_id); 97*6a5355e8SWalter Erquinigo if (!intel_pt_subtraces) 98*6a5355e8SWalter Erquinigo return intel_pt_subtraces.takeError(); 99*6a5355e8SWalter Erquinigo 100*6a5355e8SWalter Erquinigo // We'll be iterating through the thread continuous executions and the intel 101*6a5355e8SWalter Erquinigo // pt subtraces sorted by time. 102*6a5355e8SWalter Erquinigo auto it = intel_pt_subtraces->begin(); 103*6a5355e8SWalter Erquinigo auto on_new_thread_execution = 104*6a5355e8SWalter Erquinigo [&](const ThreadContinuousExecution &thread_execution) { 105*6a5355e8SWalter Erquinigo IntelPTThreadContinousExecution execution(thread_execution); 106*6a5355e8SWalter Erquinigo 107*6a5355e8SWalter Erquinigo for (; it != intel_pt_subtraces->end() && 108*6a5355e8SWalter Erquinigo it->tsc < thread_execution.GetEndTSC(); 109*6a5355e8SWalter Erquinigo it++) { 110*6a5355e8SWalter Erquinigo if (it->tsc > thread_execution.GetStartTSC()) { 111*6a5355e8SWalter Erquinigo execution.intelpt_subtraces.push_back(*it); 112*6a5355e8SWalter Erquinigo } else { 113*6a5355e8SWalter Erquinigo m_unattributed_intelpt_subtraces++; 114*6a5355e8SWalter Erquinigo } 115*6a5355e8SWalter Erquinigo } 116*6a5355e8SWalter Erquinigo continuous_executions_per_thread[thread_execution.tid].push_back( 117*6a5355e8SWalter Erquinigo execution); 118*6a5355e8SWalter Erquinigo }; 119*6a5355e8SWalter Erquinigo Error err = m_trace->OnCpuBinaryDataRead( 120*6a5355e8SWalter Erquinigo cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace, 121*6a5355e8SWalter Erquinigo [&](ArrayRef<uint8_t> data) -> Error { 122*6a5355e8SWalter Erquinigo Expected<std::vector<ThreadContinuousExecution>> executions = 123*6a5355e8SWalter Erquinigo DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion); 124*6a5355e8SWalter Erquinigo if (!executions) 125*6a5355e8SWalter Erquinigo return executions.takeError(); 126*6a5355e8SWalter Erquinigo for (const ThreadContinuousExecution &exec : *executions) 127*6a5355e8SWalter Erquinigo on_new_thread_execution(exec); 128*6a5355e8SWalter Erquinigo return Error::success(); 129*6a5355e8SWalter Erquinigo }); 130*6a5355e8SWalter Erquinigo if (err) 131*6a5355e8SWalter Erquinigo return std::move(err); 132*6a5355e8SWalter Erquinigo } 133*6a5355e8SWalter Erquinigo // We now sort the executions of each thread to have them ready for 134*6a5355e8SWalter Erquinigo // instruction decoding 135*6a5355e8SWalter Erquinigo for (auto &tid_executions : continuous_executions_per_thread) 136*6a5355e8SWalter Erquinigo std::sort(tid_executions.second.begin(), tid_executions.second.end()); 137*6a5355e8SWalter Erquinigo 138*6a5355e8SWalter Erquinigo return continuous_executions_per_thread; 139*6a5355e8SWalter Erquinigo } 140*6a5355e8SWalter Erquinigo 141*6a5355e8SWalter Erquinigo Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() { 142*6a5355e8SWalter Erquinigo if (m_setup_error) 143*6a5355e8SWalter Erquinigo return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 144*6a5355e8SWalter Erquinigo 145*6a5355e8SWalter Erquinigo if (m_continuous_executions_per_thread) 146*6a5355e8SWalter Erquinigo return Error::success(); 147*6a5355e8SWalter Erquinigo 148*6a5355e8SWalter Erquinigo Error err = m_trace->GetTimer().ForGlobal().TimeTask<Error>( 149*6a5355e8SWalter Erquinigo "Context switch and Intel PT traces correlation", [&]() -> Error { 150*6a5355e8SWalter Erquinigo if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) { 151*6a5355e8SWalter Erquinigo m_continuous_executions_per_thread.emplace(std::move(*correlation)); 152*6a5355e8SWalter Erquinigo return Error::success(); 153*6a5355e8SWalter Erquinigo } else { 154*6a5355e8SWalter Erquinigo return correlation.takeError(); 155*6a5355e8SWalter Erquinigo } 156*6a5355e8SWalter Erquinigo }); 157*6a5355e8SWalter Erquinigo if (err) { 158*6a5355e8SWalter Erquinigo m_setup_error = toString(std::move(err)); 159*6a5355e8SWalter Erquinigo return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 160*6a5355e8SWalter Erquinigo } 161*6a5355e8SWalter Erquinigo return Error::success(); 162*6a5355e8SWalter Erquinigo } 163*6a5355e8SWalter Erquinigo 164*6a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread( 165*6a5355e8SWalter Erquinigo lldb::tid_t tid) const { 166*6a5355e8SWalter Erquinigo if (!m_continuous_executions_per_thread) 167*6a5355e8SWalter Erquinigo return 0; 168*6a5355e8SWalter Erquinigo auto it = m_continuous_executions_per_thread->find(tid); 169*6a5355e8SWalter Erquinigo if (it == m_continuous_executions_per_thread->end()) 170*6a5355e8SWalter Erquinigo return 0; 171*6a5355e8SWalter Erquinigo return it->second.size(); 172*6a5355e8SWalter Erquinigo } 173*6a5355e8SWalter Erquinigo 174*6a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const { 175*6a5355e8SWalter Erquinigo if (!m_continuous_executions_per_thread) 176*6a5355e8SWalter Erquinigo return 0; 177*6a5355e8SWalter Erquinigo size_t count = 0; 178*6a5355e8SWalter Erquinigo for (const auto &kv : *m_continuous_executions_per_thread) 179*6a5355e8SWalter Erquinigo count += kv.second.size(); 180*6a5355e8SWalter Erquinigo return count; 181*6a5355e8SWalter Erquinigo } 182