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