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