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 38a7d6c3efSWalter Erquinigo Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) { 396a5355e8SWalter Erquinigo if (Error err = CorrelateContextSwitchesAndIntelPtTraces()) 40a7d6c3efSWalter Erquinigo return std::move(err); 41a7d6c3efSWalter Erquinigo 42*9f9464e0SPeicong Wu TraceIntelPTSP trace_sp = GetTrace(); 43*9f9464e0SPeicong Wu 44*9f9464e0SPeicong Wu return trace_sp 45*9f9464e0SPeicong Wu ->GetThreadTimer(thread.GetID()) 46*9f9464e0SPeicong Wu .TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> { 476a5355e8SWalter Erquinigo auto it = m_decoded_threads.find(thread.GetID()); 486a5355e8SWalter Erquinigo if (it != m_decoded_threads.end()) 496a5355e8SWalter Erquinigo return it->second; 506a5355e8SWalter Erquinigo 516a5355e8SWalter Erquinigo DecodedThreadSP decoded_thread_sp = 526a5355e8SWalter Erquinigo std::make_shared<DecodedThread>(thread.shared_from_this()); 536a5355e8SWalter Erquinigo 54ea37cd52SWalter Erquinigo Error err = trace_sp->OnAllCpusBinaryDataRead( 556a5355e8SWalter Erquinigo IntelPTDataKinds::kIptTrace, 566a5355e8SWalter Erquinigo [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error { 57*9f9464e0SPeicong Wu auto it = 58*9f9464e0SPeicong Wu m_continuous_executions_per_thread->find(thread.GetID()); 596a5355e8SWalter Erquinigo if (it != m_continuous_executions_per_thread->end()) 60*9f9464e0SPeicong Wu return DecodeSystemWideTraceForThread( 61*9f9464e0SPeicong Wu *decoded_thread_sp, *trace_sp, buffers, it->second); 626a5355e8SWalter Erquinigo 636a5355e8SWalter Erquinigo return Error::success(); 646a5355e8SWalter Erquinigo }); 656a5355e8SWalter Erquinigo if (err) 66a7d6c3efSWalter Erquinigo return std::move(err); 676a5355e8SWalter Erquinigo 686a5355e8SWalter Erquinigo m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp); 696a5355e8SWalter Erquinigo return decoded_thread_sp; 70*9f9464e0SPeicong Wu }); 716a5355e8SWalter Erquinigo } 726a5355e8SWalter Erquinigo 736a5355e8SWalter Erquinigo static Expected<std::vector<IntelPTThreadSubtrace>> 746a5355e8SWalter Erquinigo GetIntelPTSubtracesForCpu(TraceIntelPT &trace, cpu_id_t cpu_id) { 756a5355e8SWalter Erquinigo std::vector<IntelPTThreadSubtrace> intel_pt_subtraces; 766a5355e8SWalter Erquinigo Error err = trace.OnCpuBinaryDataRead( 776a5355e8SWalter Erquinigo cpu_id, IntelPTDataKinds::kIptTrace, 786a5355e8SWalter Erquinigo [&](ArrayRef<uint8_t> data) -> Error { 796a5355e8SWalter Erquinigo Expected<std::vector<IntelPTThreadSubtrace>> split_trace = 806a5355e8SWalter Erquinigo SplitTraceInContinuousExecutions(trace, data); 816a5355e8SWalter Erquinigo if (!split_trace) 826a5355e8SWalter Erquinigo return split_trace.takeError(); 836a5355e8SWalter Erquinigo 846a5355e8SWalter Erquinigo intel_pt_subtraces = std::move(*split_trace); 856a5355e8SWalter Erquinigo return Error::success(); 866a5355e8SWalter Erquinigo }); 876a5355e8SWalter Erquinigo if (err) 886a5355e8SWalter Erquinigo return std::move(err); 896a5355e8SWalter Erquinigo return intel_pt_subtraces; 906a5355e8SWalter Erquinigo } 916a5355e8SWalter Erquinigo 926a5355e8SWalter Erquinigo Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>> 936a5355e8SWalter Erquinigo TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() { 946a5355e8SWalter Erquinigo DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>> 956a5355e8SWalter Erquinigo continuous_executions_per_thread; 96ea37cd52SWalter Erquinigo TraceIntelPTSP trace_sp = GetTrace(); 976a5355e8SWalter Erquinigo 986a5355e8SWalter Erquinigo Optional<LinuxPerfZeroTscConversion> conv_opt = 99ea37cd52SWalter Erquinigo trace_sp->GetPerfZeroTscConversion(); 1006a5355e8SWalter Erquinigo if (!conv_opt) 1016a5355e8SWalter Erquinigo return createStringError( 1026a5355e8SWalter Erquinigo inconvertibleErrorCode(), 1036a5355e8SWalter Erquinigo "TSC to nanoseconds conversion values were not found"); 1046a5355e8SWalter Erquinigo 1056a5355e8SWalter Erquinigo LinuxPerfZeroTscConversion tsc_conversion = *conv_opt; 1066a5355e8SWalter Erquinigo 107ea37cd52SWalter Erquinigo for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) { 1086a5355e8SWalter Erquinigo Expected<std::vector<IntelPTThreadSubtrace>> intel_pt_subtraces = 109ea37cd52SWalter Erquinigo GetIntelPTSubtracesForCpu(*trace_sp, cpu_id); 1106a5355e8SWalter Erquinigo if (!intel_pt_subtraces) 1116a5355e8SWalter Erquinigo return intel_pt_subtraces.takeError(); 1126a5355e8SWalter Erquinigo 1136a5355e8SWalter Erquinigo // We'll be iterating through the thread continuous executions and the intel 1146a5355e8SWalter Erquinigo // pt subtraces sorted by time. 1156a5355e8SWalter Erquinigo auto it = intel_pt_subtraces->begin(); 1166a5355e8SWalter Erquinigo auto on_new_thread_execution = 1176a5355e8SWalter Erquinigo [&](const ThreadContinuousExecution &thread_execution) { 1186a5355e8SWalter Erquinigo IntelPTThreadContinousExecution execution(thread_execution); 1196a5355e8SWalter Erquinigo 1206a5355e8SWalter Erquinigo for (; it != intel_pt_subtraces->end() && 1216a5355e8SWalter Erquinigo it->tsc < thread_execution.GetEndTSC(); 1226a5355e8SWalter Erquinigo it++) { 1236a5355e8SWalter Erquinigo if (it->tsc > thread_execution.GetStartTSC()) { 1246a5355e8SWalter Erquinigo execution.intelpt_subtraces.push_back(*it); 1256a5355e8SWalter Erquinigo } else { 1266a5355e8SWalter Erquinigo m_unattributed_intelpt_subtraces++; 1276a5355e8SWalter Erquinigo } 1286a5355e8SWalter Erquinigo } 1296a5355e8SWalter Erquinigo continuous_executions_per_thread[thread_execution.tid].push_back( 1306a5355e8SWalter Erquinigo execution); 1316a5355e8SWalter Erquinigo }; 132ea37cd52SWalter Erquinigo Error err = trace_sp->OnCpuBinaryDataRead( 1336a5355e8SWalter Erquinigo cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace, 1346a5355e8SWalter Erquinigo [&](ArrayRef<uint8_t> data) -> Error { 1356a5355e8SWalter Erquinigo Expected<std::vector<ThreadContinuousExecution>> executions = 1366a5355e8SWalter Erquinigo DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion); 1376a5355e8SWalter Erquinigo if (!executions) 1386a5355e8SWalter Erquinigo return executions.takeError(); 1396a5355e8SWalter Erquinigo for (const ThreadContinuousExecution &exec : *executions) 1406a5355e8SWalter Erquinigo on_new_thread_execution(exec); 1416a5355e8SWalter Erquinigo return Error::success(); 1426a5355e8SWalter Erquinigo }); 1436a5355e8SWalter Erquinigo if (err) 1446a5355e8SWalter Erquinigo return std::move(err); 1456a5355e8SWalter Erquinigo } 1466a5355e8SWalter Erquinigo // We now sort the executions of each thread to have them ready for 1476a5355e8SWalter Erquinigo // instruction decoding 1486a5355e8SWalter Erquinigo for (auto &tid_executions : continuous_executions_per_thread) 1496a5355e8SWalter Erquinigo std::sort(tid_executions.second.begin(), tid_executions.second.end()); 1506a5355e8SWalter Erquinigo 1516a5355e8SWalter Erquinigo return continuous_executions_per_thread; 1526a5355e8SWalter Erquinigo } 1536a5355e8SWalter Erquinigo 1546a5355e8SWalter Erquinigo Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() { 1556a5355e8SWalter Erquinigo if (m_setup_error) 1566a5355e8SWalter Erquinigo return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 1576a5355e8SWalter Erquinigo 1586a5355e8SWalter Erquinigo if (m_continuous_executions_per_thread) 1596a5355e8SWalter Erquinigo return Error::success(); 1606a5355e8SWalter Erquinigo 161*9f9464e0SPeicong Wu Error err = GetTrace()->GetGlobalTimer().TimeTask( 1626a5355e8SWalter Erquinigo "Context switch and Intel PT traces correlation", [&]() -> Error { 1636a5355e8SWalter Erquinigo if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) { 1646a5355e8SWalter Erquinigo m_continuous_executions_per_thread.emplace(std::move(*correlation)); 1656a5355e8SWalter Erquinigo return Error::success(); 1666a5355e8SWalter Erquinigo } else { 1676a5355e8SWalter Erquinigo return correlation.takeError(); 1686a5355e8SWalter Erquinigo } 1696a5355e8SWalter Erquinigo }); 1706a5355e8SWalter Erquinigo if (err) { 1716a5355e8SWalter Erquinigo m_setup_error = toString(std::move(err)); 1726a5355e8SWalter Erquinigo return createStringError(inconvertibleErrorCode(), m_setup_error->c_str()); 1736a5355e8SWalter Erquinigo } 1746a5355e8SWalter Erquinigo return Error::success(); 1756a5355e8SWalter Erquinigo } 1766a5355e8SWalter Erquinigo 1776a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread( 1786a5355e8SWalter Erquinigo lldb::tid_t tid) const { 1796a5355e8SWalter Erquinigo if (!m_continuous_executions_per_thread) 1806a5355e8SWalter Erquinigo return 0; 1816a5355e8SWalter Erquinigo auto it = m_continuous_executions_per_thread->find(tid); 1826a5355e8SWalter Erquinigo if (it == m_continuous_executions_per_thread->end()) 1836a5355e8SWalter Erquinigo return 0; 1846a5355e8SWalter Erquinigo return it->second.size(); 1856a5355e8SWalter Erquinigo } 1866a5355e8SWalter Erquinigo 1876a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const { 1886a5355e8SWalter Erquinigo if (!m_continuous_executions_per_thread) 1896a5355e8SWalter Erquinigo return 0; 1906a5355e8SWalter Erquinigo size_t count = 0; 1916a5355e8SWalter Erquinigo for (const auto &kv : *m_continuous_executions_per_thread) 1926a5355e8SWalter Erquinigo count += kv.second.size(); 1936a5355e8SWalter Erquinigo return count; 1946a5355e8SWalter Erquinigo } 195