1 //===-- TraceIntelPTMultiCpuDecoder.cpp -----------------------------------===// 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<Optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() { 39 Optional<uint64_t> lowest_tsc; 40 TraceIntelPTSP trace_sp = GetTrace(); 41 42 Error err = GetTrace()->OnAllCpusBinaryDataRead( 43 IntelPTDataKinds::kIptTrace, 44 [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error { 45 for (auto &cpu_id_to_buffer : buffers) { 46 Expected<Optional<uint64_t>> tsc = 47 FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second); 48 if (!tsc) 49 return tsc.takeError(); 50 if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc)) 51 lowest_tsc = **tsc; 52 } 53 return Error::success(); 54 }); 55 if (err) 56 return std::move(err); 57 return lowest_tsc; 58 } 59 60 Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) { 61 if (Error err = CorrelateContextSwitchesAndIntelPtTraces()) 62 return std::move(err); 63 64 TraceIntelPTSP trace_sp = GetTrace(); 65 66 return trace_sp 67 ->GetThreadTimer(thread.GetID()) 68 .TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> { 69 auto it = m_decoded_threads.find(thread.GetID()); 70 if (it != m_decoded_threads.end()) 71 return it->second; 72 73 DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>( 74 thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion()); 75 76 Error err = trace_sp->OnAllCpusBinaryDataRead( 77 IntelPTDataKinds::kIptTrace, 78 [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error { 79 auto it = 80 m_continuous_executions_per_thread->find(thread.GetID()); 81 if (it != m_continuous_executions_per_thread->end()) 82 return DecodeSystemWideTraceForThread( 83 *decoded_thread_sp, *trace_sp, buffers, it->second); 84 85 return Error::success(); 86 }); 87 if (err) 88 return std::move(err); 89 90 m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp); 91 return decoded_thread_sp; 92 }); 93 } 94 95 static Expected<std::vector<IntelPTThreadSubtrace>> 96 GetIntelPTSubtracesForCpu(TraceIntelPT &trace, cpu_id_t cpu_id) { 97 std::vector<IntelPTThreadSubtrace> intel_pt_subtraces; 98 Error err = trace.OnCpuBinaryDataRead( 99 cpu_id, IntelPTDataKinds::kIptTrace, 100 [&](ArrayRef<uint8_t> data) -> Error { 101 Expected<std::vector<IntelPTThreadSubtrace>> split_trace = 102 SplitTraceInContinuousExecutions(trace, data); 103 if (!split_trace) 104 return split_trace.takeError(); 105 106 intel_pt_subtraces = std::move(*split_trace); 107 return Error::success(); 108 }); 109 if (err) 110 return std::move(err); 111 return intel_pt_subtraces; 112 } 113 114 Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>> 115 TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() { 116 DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>> 117 continuous_executions_per_thread; 118 TraceIntelPTSP trace_sp = GetTrace(); 119 120 Optional<LinuxPerfZeroTscConversion> conv_opt = 121 trace_sp->GetPerfZeroTscConversion(); 122 if (!conv_opt) 123 return createStringError( 124 inconvertibleErrorCode(), 125 "TSC to nanoseconds conversion values were not found"); 126 127 LinuxPerfZeroTscConversion tsc_conversion = *conv_opt; 128 129 for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) { 130 Expected<std::vector<IntelPTThreadSubtrace>> intel_pt_subtraces = 131 GetIntelPTSubtracesForCpu(*trace_sp, cpu_id); 132 if (!intel_pt_subtraces) 133 return intel_pt_subtraces.takeError(); 134 135 m_total_psb_blocks += intel_pt_subtraces->size(); 136 // We'll be iterating through the thread continuous executions and the intel 137 // pt subtraces sorted by time. 138 auto it = intel_pt_subtraces->begin(); 139 auto on_new_thread_execution = 140 [&](const ThreadContinuousExecution &thread_execution) { 141 IntelPTThreadContinousExecution execution(thread_execution); 142 143 for (; it != intel_pt_subtraces->end() && 144 it->tsc < thread_execution.GetEndTSC(); 145 it++) { 146 if (it->tsc > thread_execution.GetStartTSC()) { 147 execution.intelpt_subtraces.push_back(*it); 148 } else { 149 m_unattributed_psb_blocks++; 150 } 151 } 152 continuous_executions_per_thread[thread_execution.tid].push_back( 153 execution); 154 }; 155 Error err = trace_sp->OnCpuBinaryDataRead( 156 cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace, 157 [&](ArrayRef<uint8_t> data) -> Error { 158 Expected<std::vector<ThreadContinuousExecution>> executions = 159 DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion); 160 if (!executions) 161 return executions.takeError(); 162 for (const ThreadContinuousExecution &exec : *executions) 163 on_new_thread_execution(exec); 164 return Error::success(); 165 }); 166 if (err) 167 return std::move(err); 168 169 m_unattributed_psb_blocks += intel_pt_subtraces->end() - it; 170 } 171 // We now sort the executions of each thread to have them ready for 172 // instruction decoding 173 for (auto &tid_executions : continuous_executions_per_thread) 174 std::sort(tid_executions.second.begin(), tid_executions.second.end()); 175 176 return continuous_executions_per_thread; 177 } 178 179 Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() { 180 if (m_setup_error) 181 return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 182 183 if (m_continuous_executions_per_thread) 184 return Error::success(); 185 186 Error err = GetTrace()->GetGlobalTimer().TimeTask( 187 "Context switch and Intel PT traces correlation", [&]() -> Error { 188 if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) { 189 m_continuous_executions_per_thread.emplace(std::move(*correlation)); 190 return Error::success(); 191 } else { 192 return correlation.takeError(); 193 } 194 }); 195 if (err) { 196 m_setup_error = toString(std::move(err)); 197 return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 198 } 199 return Error::success(); 200 } 201 202 size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread( 203 lldb::tid_t tid) const { 204 if (!m_continuous_executions_per_thread) 205 return 0; 206 auto it = m_continuous_executions_per_thread->find(tid); 207 if (it == m_continuous_executions_per_thread->end()) 208 return 0; 209 return it->second.size(); 210 } 211 212 size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const { 213 if (!m_continuous_executions_per_thread) 214 return 0; 215 size_t count = 0; 216 for (const auto &kv : *m_continuous_executions_per_thread) 217 count += kv.second.size(); 218 return count; 219 } 220 221 size_t 222 TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const { 223 if (!m_continuous_executions_per_thread) 224 return 0; 225 size_t count = 0; 226 auto it = m_continuous_executions_per_thread->find(tid); 227 if (it == m_continuous_executions_per_thread->end()) 228 return 0; 229 for (const IntelPTThreadContinousExecution &execution : it->second) 230 count += execution.intelpt_subtraces.size(); 231 return count; 232 } 233 234 size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const { 235 return m_unattributed_psb_blocks; 236 } 237 238 size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const { 239 return m_total_psb_blocks; 240 } 241