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