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 m_total_psb_blocks += intel_pt_subtraces->size(); 114 // We'll be iterating through the thread continuous executions and the intel 115 // pt subtraces sorted by time. 116 auto it = intel_pt_subtraces->begin(); 117 auto on_new_thread_execution = 118 [&](const ThreadContinuousExecution &thread_execution) { 119 IntelPTThreadContinousExecution execution(thread_execution); 120 121 for (; it != intel_pt_subtraces->end() && 122 it->tsc < thread_execution.GetEndTSC(); 123 it++) { 124 if (it->tsc > thread_execution.GetStartTSC()) { 125 execution.intelpt_subtraces.push_back(*it); 126 } else { 127 m_unattributed_psb_blocks++; 128 } 129 } 130 continuous_executions_per_thread[thread_execution.tid].push_back( 131 execution); 132 }; 133 Error err = trace_sp->OnCpuBinaryDataRead( 134 cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace, 135 [&](ArrayRef<uint8_t> data) -> Error { 136 Expected<std::vector<ThreadContinuousExecution>> executions = 137 DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion); 138 if (!executions) 139 return executions.takeError(); 140 for (const ThreadContinuousExecution &exec : *executions) 141 on_new_thread_execution(exec); 142 return Error::success(); 143 }); 144 if (err) 145 return std::move(err); 146 147 m_unattributed_psb_blocks += intel_pt_subtraces->end() - it; 148 } 149 // We now sort the executions of each thread to have them ready for 150 // instruction decoding 151 for (auto &tid_executions : continuous_executions_per_thread) 152 std::sort(tid_executions.second.begin(), tid_executions.second.end()); 153 154 return continuous_executions_per_thread; 155 } 156 157 Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() { 158 if (m_setup_error) 159 return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 160 161 if (m_continuous_executions_per_thread) 162 return Error::success(); 163 164 Error err = GetTrace()->GetGlobalTimer().TimeTask( 165 "Context switch and Intel PT traces correlation", [&]() -> Error { 166 if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) { 167 m_continuous_executions_per_thread.emplace(std::move(*correlation)); 168 return Error::success(); 169 } else { 170 return correlation.takeError(); 171 } 172 }); 173 if (err) { 174 m_setup_error = toString(std::move(err)); 175 return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 176 } 177 return Error::success(); 178 } 179 180 size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread( 181 lldb::tid_t tid) const { 182 if (!m_continuous_executions_per_thread) 183 return 0; 184 auto it = m_continuous_executions_per_thread->find(tid); 185 if (it == m_continuous_executions_per_thread->end()) 186 return 0; 187 return it->second.size(); 188 } 189 190 size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const { 191 if (!m_continuous_executions_per_thread) 192 return 0; 193 size_t count = 0; 194 for (const auto &kv : *m_continuous_executions_per_thread) 195 count += kv.second.size(); 196 return count; 197 } 198 199 size_t 200 TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const { 201 if (!m_continuous_executions_per_thread) 202 return 0; 203 size_t count = 0; 204 auto it = m_continuous_executions_per_thread->find(tid); 205 for (const IntelPTThreadContinousExecution &execution : it->second) 206 count += execution.intelpt_subtraces.size(); 207 return count; 208 } 209 210 size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const { 211 return m_unattributed_psb_blocks; 212 } 213 214 size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const { 215 return m_total_psb_blocks; 216 } 217