16a5355e8SWalter Erquinigo //===-- TraceIntelPTMultiCpuDecoder.cpp ----0------------------------------===// 26a5355e8SWalter Erquinigo // 36a5355e8SWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 46a5355e8SWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information. 56a5355e8SWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 66a5355e8SWalter Erquinigo // 76a5355e8SWalter Erquinigo //===----------------------------------------------------------------------===// 86a5355e8SWalter Erquinigo 96a5355e8SWalter Erquinigo #include "TraceIntelPTMultiCpuDecoder.h" 106a5355e8SWalter Erquinigo 116a5355e8SWalter Erquinigo #include "TraceIntelPT.h" 126a5355e8SWalter Erquinigo 136a5355e8SWalter Erquinigo #include "llvm/Support/Error.h" 146a5355e8SWalter Erquinigo 156a5355e8SWalter Erquinigo using namespace lldb; 166a5355e8SWalter Erquinigo using namespace lldb_private; 176a5355e8SWalter Erquinigo using namespace lldb_private::trace_intel_pt; 186a5355e8SWalter Erquinigo using namespace llvm; 196a5355e8SWalter Erquinigo 20ea37cd52SWalter Erquinigo TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder( 21ea37cd52SWalter Erquinigo TraceIntelPTSP trace_sp) 22ea37cd52SWalter Erquinigo : m_trace_wp(trace_sp) { 23ea37cd52SWalter Erquinigo for (Process *proc : trace_sp->GetAllProcesses()) { 246a5355e8SWalter Erquinigo for (ThreadSP thread_sp : proc->GetThreadList().Threads()) { 256a5355e8SWalter Erquinigo m_tids.insert(thread_sp->GetID()); 266a5355e8SWalter Erquinigo } 276a5355e8SWalter Erquinigo } 286a5355e8SWalter Erquinigo } 296a5355e8SWalter Erquinigo 30ea37cd52SWalter Erquinigo TraceIntelPTSP TraceIntelPTMultiCpuDecoder::GetTrace() { 31ea37cd52SWalter Erquinigo return m_trace_wp.lock(); 32ea37cd52SWalter Erquinigo } 33ea37cd52SWalter Erquinigo 346a5355e8SWalter Erquinigo bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const { 356a5355e8SWalter Erquinigo return m_tids.count(tid); 366a5355e8SWalter Erquinigo } 376a5355e8SWalter Erquinigo 38*a7d6c3efSWalter Erquinigo Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) { 396a5355e8SWalter Erquinigo if (Error err = CorrelateContextSwitchesAndIntelPtTraces()) 40*a7d6c3efSWalter Erquinigo return std::move(err); 41*a7d6c3efSWalter Erquinigo 426a5355e8SWalter Erquinigo auto it = m_decoded_threads.find(thread.GetID()); 436a5355e8SWalter Erquinigo if (it != m_decoded_threads.end()) 446a5355e8SWalter Erquinigo return it->second; 456a5355e8SWalter Erquinigo 466a5355e8SWalter Erquinigo DecodedThreadSP decoded_thread_sp = 476a5355e8SWalter Erquinigo std::make_shared<DecodedThread>(thread.shared_from_this()); 486a5355e8SWalter Erquinigo 49ea37cd52SWalter Erquinigo TraceIntelPTSP trace_sp = GetTrace(); 50ea37cd52SWalter Erquinigo 51ea37cd52SWalter Erquinigo Error err = trace_sp->OnAllCpusBinaryDataRead( 526a5355e8SWalter Erquinigo IntelPTDataKinds::kIptTrace, 536a5355e8SWalter Erquinigo [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error { 546a5355e8SWalter Erquinigo auto it = m_continuous_executions_per_thread->find(thread.GetID()); 556a5355e8SWalter Erquinigo if (it != m_continuous_executions_per_thread->end()) 56*a7d6c3efSWalter Erquinigo return DecodeSystemWideTraceForThread(*decoded_thread_sp, *trace_sp, 57*a7d6c3efSWalter Erquinigo buffers, it->second); 586a5355e8SWalter Erquinigo 596a5355e8SWalter Erquinigo return Error::success(); 606a5355e8SWalter Erquinigo }); 616a5355e8SWalter Erquinigo if (err) 62*a7d6c3efSWalter Erquinigo return std::move(err); 636a5355e8SWalter Erquinigo 646a5355e8SWalter Erquinigo m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp); 656a5355e8SWalter Erquinigo return decoded_thread_sp; 666a5355e8SWalter Erquinigo } 676a5355e8SWalter Erquinigo 686a5355e8SWalter Erquinigo static Expected<std::vector<IntelPTThreadSubtrace>> 696a5355e8SWalter Erquinigo GetIntelPTSubtracesForCpu(TraceIntelPT &trace, cpu_id_t cpu_id) { 706a5355e8SWalter Erquinigo std::vector<IntelPTThreadSubtrace> intel_pt_subtraces; 716a5355e8SWalter Erquinigo Error err = trace.OnCpuBinaryDataRead( 726a5355e8SWalter Erquinigo cpu_id, IntelPTDataKinds::kIptTrace, 736a5355e8SWalter Erquinigo [&](ArrayRef<uint8_t> data) -> Error { 746a5355e8SWalter Erquinigo Expected<std::vector<IntelPTThreadSubtrace>> split_trace = 756a5355e8SWalter Erquinigo SplitTraceInContinuousExecutions(trace, data); 766a5355e8SWalter Erquinigo if (!split_trace) 776a5355e8SWalter Erquinigo return split_trace.takeError(); 786a5355e8SWalter Erquinigo 796a5355e8SWalter Erquinigo intel_pt_subtraces = std::move(*split_trace); 806a5355e8SWalter Erquinigo return Error::success(); 816a5355e8SWalter Erquinigo }); 826a5355e8SWalter Erquinigo if (err) 836a5355e8SWalter Erquinigo return std::move(err); 846a5355e8SWalter Erquinigo return intel_pt_subtraces; 856a5355e8SWalter Erquinigo } 866a5355e8SWalter Erquinigo 876a5355e8SWalter Erquinigo Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>> 886a5355e8SWalter Erquinigo TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() { 896a5355e8SWalter Erquinigo DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>> 906a5355e8SWalter Erquinigo continuous_executions_per_thread; 91ea37cd52SWalter Erquinigo TraceIntelPTSP trace_sp = GetTrace(); 926a5355e8SWalter Erquinigo 936a5355e8SWalter Erquinigo Optional<LinuxPerfZeroTscConversion> conv_opt = 94ea37cd52SWalter Erquinigo trace_sp->GetPerfZeroTscConversion(); 956a5355e8SWalter Erquinigo if (!conv_opt) 966a5355e8SWalter Erquinigo return createStringError( 976a5355e8SWalter Erquinigo inconvertibleErrorCode(), 986a5355e8SWalter Erquinigo "TSC to nanoseconds conversion values were not found"); 996a5355e8SWalter Erquinigo 1006a5355e8SWalter Erquinigo LinuxPerfZeroTscConversion tsc_conversion = *conv_opt; 1016a5355e8SWalter Erquinigo 102ea37cd52SWalter Erquinigo for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) { 1036a5355e8SWalter Erquinigo Expected<std::vector<IntelPTThreadSubtrace>> intel_pt_subtraces = 104ea37cd52SWalter Erquinigo GetIntelPTSubtracesForCpu(*trace_sp, cpu_id); 1056a5355e8SWalter Erquinigo if (!intel_pt_subtraces) 1066a5355e8SWalter Erquinigo return intel_pt_subtraces.takeError(); 1076a5355e8SWalter Erquinigo 1086a5355e8SWalter Erquinigo // We'll be iterating through the thread continuous executions and the intel 1096a5355e8SWalter Erquinigo // pt subtraces sorted by time. 1106a5355e8SWalter Erquinigo auto it = intel_pt_subtraces->begin(); 1116a5355e8SWalter Erquinigo auto on_new_thread_execution = 1126a5355e8SWalter Erquinigo [&](const ThreadContinuousExecution &thread_execution) { 1136a5355e8SWalter Erquinigo IntelPTThreadContinousExecution execution(thread_execution); 1146a5355e8SWalter Erquinigo 1156a5355e8SWalter Erquinigo for (; it != intel_pt_subtraces->end() && 1166a5355e8SWalter Erquinigo it->tsc < thread_execution.GetEndTSC(); 1176a5355e8SWalter Erquinigo it++) { 1186a5355e8SWalter Erquinigo if (it->tsc > thread_execution.GetStartTSC()) { 1196a5355e8SWalter Erquinigo execution.intelpt_subtraces.push_back(*it); 1206a5355e8SWalter Erquinigo } else { 1216a5355e8SWalter Erquinigo m_unattributed_intelpt_subtraces++; 1226a5355e8SWalter Erquinigo } 1236a5355e8SWalter Erquinigo } 1246a5355e8SWalter Erquinigo continuous_executions_per_thread[thread_execution.tid].push_back( 1256a5355e8SWalter Erquinigo execution); 1266a5355e8SWalter Erquinigo }; 127ea37cd52SWalter Erquinigo Error err = trace_sp->OnCpuBinaryDataRead( 1286a5355e8SWalter Erquinigo cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace, 1296a5355e8SWalter Erquinigo [&](ArrayRef<uint8_t> data) -> Error { 1306a5355e8SWalter Erquinigo Expected<std::vector<ThreadContinuousExecution>> executions = 1316a5355e8SWalter Erquinigo DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion); 1326a5355e8SWalter Erquinigo if (!executions) 1336a5355e8SWalter Erquinigo return executions.takeError(); 1346a5355e8SWalter Erquinigo for (const ThreadContinuousExecution &exec : *executions) 1356a5355e8SWalter Erquinigo on_new_thread_execution(exec); 1366a5355e8SWalter Erquinigo return Error::success(); 1376a5355e8SWalter Erquinigo }); 1386a5355e8SWalter Erquinigo if (err) 1396a5355e8SWalter Erquinigo return std::move(err); 1406a5355e8SWalter Erquinigo } 1416a5355e8SWalter Erquinigo // We now sort the executions of each thread to have them ready for 1426a5355e8SWalter Erquinigo // instruction decoding 1436a5355e8SWalter Erquinigo for (auto &tid_executions : continuous_executions_per_thread) 1446a5355e8SWalter Erquinigo std::sort(tid_executions.second.begin(), tid_executions.second.end()); 1456a5355e8SWalter Erquinigo 1466a5355e8SWalter Erquinigo return continuous_executions_per_thread; 1476a5355e8SWalter Erquinigo } 1486a5355e8SWalter Erquinigo 1496a5355e8SWalter Erquinigo Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() { 1506a5355e8SWalter Erquinigo if (m_setup_error) 1516a5355e8SWalter Erquinigo return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 1526a5355e8SWalter Erquinigo 1536a5355e8SWalter Erquinigo if (m_continuous_executions_per_thread) 1546a5355e8SWalter Erquinigo return Error::success(); 1556a5355e8SWalter Erquinigo 156ea37cd52SWalter Erquinigo Error err = GetTrace()->GetTimer().ForGlobal().TimeTask<Error>( 1576a5355e8SWalter Erquinigo "Context switch and Intel PT traces correlation", [&]() -> Error { 1586a5355e8SWalter Erquinigo if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) { 1596a5355e8SWalter Erquinigo m_continuous_executions_per_thread.emplace(std::move(*correlation)); 1606a5355e8SWalter Erquinigo return Error::success(); 1616a5355e8SWalter Erquinigo } else { 1626a5355e8SWalter Erquinigo return correlation.takeError(); 1636a5355e8SWalter Erquinigo } 1646a5355e8SWalter Erquinigo }); 1656a5355e8SWalter Erquinigo if (err) { 1666a5355e8SWalter Erquinigo m_setup_error = toString(std::move(err)); 1676a5355e8SWalter Erquinigo return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 1686a5355e8SWalter Erquinigo } 1696a5355e8SWalter Erquinigo return Error::success(); 1706a5355e8SWalter Erquinigo } 1716a5355e8SWalter Erquinigo 1726a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread( 1736a5355e8SWalter Erquinigo lldb::tid_t tid) const { 1746a5355e8SWalter Erquinigo if (!m_continuous_executions_per_thread) 1756a5355e8SWalter Erquinigo return 0; 1766a5355e8SWalter Erquinigo auto it = m_continuous_executions_per_thread->find(tid); 1776a5355e8SWalter Erquinigo if (it == m_continuous_executions_per_thread->end()) 1786a5355e8SWalter Erquinigo return 0; 1796a5355e8SWalter Erquinigo return it->second.size(); 1806a5355e8SWalter Erquinigo } 1816a5355e8SWalter Erquinigo 1826a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const { 1836a5355e8SWalter Erquinigo if (!m_continuous_executions_per_thread) 1846a5355e8SWalter Erquinigo return 0; 1856a5355e8SWalter Erquinigo size_t count = 0; 1866a5355e8SWalter Erquinigo for (const auto &kv : *m_continuous_executions_per_thread) 1876a5355e8SWalter Erquinigo count += kv.second.size(); 1886a5355e8SWalter Erquinigo return count; 1896a5355e8SWalter Erquinigo } 190