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