xref: /llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp (revision 2fe8327406050d2585d2ced910a678e28caefcf5)
10466d1dfSymeng //===-- TraceIntelPTMultiCpuDecoder.cpp -----------------------------------===//
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 #include "TraceIntelPT.h"
116a5355e8SWalter Erquinigo #include "llvm/Support/Error.h"
12f190ce62SKazu Hirata #include <optional>
136a5355e8SWalter Erquinigo 
146a5355e8SWalter Erquinigo using namespace lldb;
156a5355e8SWalter Erquinigo using namespace lldb_private;
166a5355e8SWalter Erquinigo using namespace lldb_private::trace_intel_pt;
176a5355e8SWalter Erquinigo using namespace llvm;
186a5355e8SWalter Erquinigo 
TraceIntelPTMultiCpuDecoder(TraceIntelPTSP trace_sp)19ea37cd52SWalter Erquinigo TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder(
20ea37cd52SWalter Erquinigo     TraceIntelPTSP trace_sp)
21ea37cd52SWalter Erquinigo     : m_trace_wp(trace_sp) {
22ea37cd52SWalter Erquinigo   for (Process *proc : trace_sp->GetAllProcesses()) {
236a5355e8SWalter Erquinigo     for (ThreadSP thread_sp : proc->GetThreadList().Threads()) {
246a5355e8SWalter Erquinigo       m_tids.insert(thread_sp->GetID());
256a5355e8SWalter Erquinigo     }
266a5355e8SWalter Erquinigo   }
276a5355e8SWalter Erquinigo }
286a5355e8SWalter Erquinigo 
GetTrace()29ea37cd52SWalter Erquinigo TraceIntelPTSP TraceIntelPTMultiCpuDecoder::GetTrace() {
30ea37cd52SWalter Erquinigo   return m_trace_wp.lock();
31ea37cd52SWalter Erquinigo }
32ea37cd52SWalter Erquinigo 
TracesThread(lldb::tid_t tid) const336a5355e8SWalter Erquinigo bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const {
346a5355e8SWalter Erquinigo   return m_tids.count(tid);
356a5355e8SWalter Erquinigo }
366a5355e8SWalter Erquinigo 
FindLowestTSC()37*2fe83274SKazu Hirata Expected<std::optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() {
38*2fe83274SKazu Hirata   std::optional<uint64_t> lowest_tsc;
394f676c25SWalter Erquinigo   TraceIntelPTSP trace_sp = GetTrace();
404f676c25SWalter Erquinigo 
414f676c25SWalter Erquinigo   Error err = GetTrace()->OnAllCpusBinaryDataRead(
424f676c25SWalter Erquinigo       IntelPTDataKinds::kIptTrace,
434f676c25SWalter Erquinigo       [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
444f676c25SWalter Erquinigo         for (auto &cpu_id_to_buffer : buffers) {
45*2fe83274SKazu Hirata           Expected<std::optional<uint64_t>> tsc =
464f676c25SWalter Erquinigo               FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second);
474f676c25SWalter Erquinigo           if (!tsc)
484f676c25SWalter Erquinigo             return tsc.takeError();
494f676c25SWalter Erquinigo           if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
504f676c25SWalter Erquinigo             lowest_tsc = **tsc;
514f676c25SWalter Erquinigo         }
524f676c25SWalter Erquinigo         return Error::success();
534f676c25SWalter Erquinigo       });
544f676c25SWalter Erquinigo   if (err)
554f676c25SWalter Erquinigo     return std::move(err);
564f676c25SWalter Erquinigo   return lowest_tsc;
574f676c25SWalter Erquinigo }
584f676c25SWalter Erquinigo 
Decode(Thread & thread)59a7d6c3efSWalter Erquinigo Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
606a5355e8SWalter Erquinigo   if (Error err = CorrelateContextSwitchesAndIntelPtTraces())
61a7d6c3efSWalter Erquinigo     return std::move(err);
62a7d6c3efSWalter Erquinigo 
639f9464e0SPeicong Wu   TraceIntelPTSP trace_sp = GetTrace();
649f9464e0SPeicong Wu 
65d179ea12SWalter Erquinigo   return trace_sp->GetThreadTimer(thread.GetID())
669f9464e0SPeicong Wu       .TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> {
676a5355e8SWalter Erquinigo         auto it = m_decoded_threads.find(thread.GetID());
686a5355e8SWalter Erquinigo         if (it != m_decoded_threads.end())
696a5355e8SWalter Erquinigo           return it->second;
706a5355e8SWalter Erquinigo 
714f676c25SWalter Erquinigo         DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(
724f676c25SWalter Erquinigo             thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion());
736a5355e8SWalter Erquinigo 
74ea37cd52SWalter Erquinigo         Error err = trace_sp->OnAllCpusBinaryDataRead(
756a5355e8SWalter Erquinigo             IntelPTDataKinds::kIptTrace,
766a5355e8SWalter Erquinigo             [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
779f9464e0SPeicong Wu               auto it =
789f9464e0SPeicong Wu                   m_continuous_executions_per_thread->find(thread.GetID());
796a5355e8SWalter Erquinigo               if (it != m_continuous_executions_per_thread->end())
809f9464e0SPeicong Wu                 return DecodeSystemWideTraceForThread(
819f9464e0SPeicong Wu                     *decoded_thread_sp, *trace_sp, buffers, it->second);
826a5355e8SWalter Erquinigo 
836a5355e8SWalter Erquinigo               return Error::success();
846a5355e8SWalter Erquinigo             });
856a5355e8SWalter Erquinigo         if (err)
86a7d6c3efSWalter Erquinigo           return std::move(err);
876a5355e8SWalter Erquinigo 
886a5355e8SWalter Erquinigo         m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp);
896a5355e8SWalter Erquinigo         return decoded_thread_sp;
909f9464e0SPeicong Wu       });
916a5355e8SWalter Erquinigo }
926a5355e8SWalter Erquinigo 
GetPSBBlocksForCPU(TraceIntelPT & trace,cpu_id_t cpu_id)93e17cae07SWalter Erquinigo static Expected<std::vector<PSBBlock>> GetPSBBlocksForCPU(TraceIntelPT &trace,
94e17cae07SWalter Erquinigo                                                           cpu_id_t cpu_id) {
95e17cae07SWalter Erquinigo   std::vector<PSBBlock> psb_blocks;
966a5355e8SWalter Erquinigo   Error err = trace.OnCpuBinaryDataRead(
976a5355e8SWalter Erquinigo       cpu_id, IntelPTDataKinds::kIptTrace,
986a5355e8SWalter Erquinigo       [&](ArrayRef<uint8_t> data) -> Error {
99e17cae07SWalter Erquinigo         Expected<std::vector<PSBBlock>> split_trace =
100e17cae07SWalter Erquinigo             SplitTraceIntoPSBBlock(trace, data, /*expect_tscs=*/true);
1016a5355e8SWalter Erquinigo         if (!split_trace)
1026a5355e8SWalter Erquinigo           return split_trace.takeError();
1036a5355e8SWalter Erquinigo 
104e17cae07SWalter Erquinigo         psb_blocks = std::move(*split_trace);
1056a5355e8SWalter Erquinigo         return Error::success();
1066a5355e8SWalter Erquinigo       });
1076a5355e8SWalter Erquinigo   if (err)
1086a5355e8SWalter Erquinigo     return std::move(err);
109e17cae07SWalter Erquinigo   return psb_blocks;
1106a5355e8SWalter Erquinigo }
1116a5355e8SWalter Erquinigo 
1126a5355e8SWalter Erquinigo Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
DoCorrelateContextSwitchesAndIntelPtTraces()1136a5355e8SWalter Erquinigo TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {
1146a5355e8SWalter Erquinigo   DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>
1156a5355e8SWalter Erquinigo       continuous_executions_per_thread;
116ea37cd52SWalter Erquinigo   TraceIntelPTSP trace_sp = GetTrace();
1176a5355e8SWalter Erquinigo 
118*2fe83274SKazu Hirata   std::optional<LinuxPerfZeroTscConversion> conv_opt =
119ea37cd52SWalter Erquinigo       trace_sp->GetPerfZeroTscConversion();
1206a5355e8SWalter Erquinigo   if (!conv_opt)
1216a5355e8SWalter Erquinigo     return createStringError(
1226a5355e8SWalter Erquinigo         inconvertibleErrorCode(),
1236a5355e8SWalter Erquinigo         "TSC to nanoseconds conversion values were not found");
1246a5355e8SWalter Erquinigo 
1256a5355e8SWalter Erquinigo   LinuxPerfZeroTscConversion tsc_conversion = *conv_opt;
1266a5355e8SWalter Erquinigo 
127ea37cd52SWalter Erquinigo   for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) {
128e17cae07SWalter Erquinigo     Expected<std::vector<PSBBlock>> psb_blocks =
129e17cae07SWalter Erquinigo         GetPSBBlocksForCPU(*trace_sp, cpu_id);
130e17cae07SWalter Erquinigo     if (!psb_blocks)
131e17cae07SWalter Erquinigo       return psb_blocks.takeError();
1326a5355e8SWalter Erquinigo 
133e17cae07SWalter Erquinigo     m_total_psb_blocks += psb_blocks->size();
1346a5355e8SWalter Erquinigo     // We'll be iterating through the thread continuous executions and the intel
1356a5355e8SWalter Erquinigo     // pt subtraces sorted by time.
136e17cae07SWalter Erquinigo     auto it = psb_blocks->begin();
1376a5355e8SWalter Erquinigo     auto on_new_thread_execution =
1386a5355e8SWalter Erquinigo         [&](const ThreadContinuousExecution &thread_execution) {
1396a5355e8SWalter Erquinigo           IntelPTThreadContinousExecution execution(thread_execution);
1406a5355e8SWalter Erquinigo 
141e17cae07SWalter Erquinigo           for (; it != psb_blocks->end() &&
142e17cae07SWalter Erquinigo                  *it->tsc < thread_execution.GetEndTSC();
1436a5355e8SWalter Erquinigo                it++) {
144e17cae07SWalter Erquinigo             if (*it->tsc > thread_execution.GetStartTSC()) {
145e17cae07SWalter Erquinigo               execution.psb_blocks.push_back(*it);
1466a5355e8SWalter Erquinigo             } else {
147d30fd5c3SGaurav Gaur               m_unattributed_psb_blocks++;
1486a5355e8SWalter Erquinigo             }
1496a5355e8SWalter Erquinigo           }
1506a5355e8SWalter Erquinigo           continuous_executions_per_thread[thread_execution.tid].push_back(
1516a5355e8SWalter Erquinigo               execution);
1526a5355e8SWalter Erquinigo         };
153ea37cd52SWalter Erquinigo     Error err = trace_sp->OnCpuBinaryDataRead(
1546a5355e8SWalter Erquinigo         cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,
1556a5355e8SWalter Erquinigo         [&](ArrayRef<uint8_t> data) -> Error {
1566a5355e8SWalter Erquinigo           Expected<std::vector<ThreadContinuousExecution>> executions =
1576a5355e8SWalter Erquinigo               DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion);
1586a5355e8SWalter Erquinigo           if (!executions)
1596a5355e8SWalter Erquinigo             return executions.takeError();
1606a5355e8SWalter Erquinigo           for (const ThreadContinuousExecution &exec : *executions)
1616a5355e8SWalter Erquinigo             on_new_thread_execution(exec);
1626a5355e8SWalter Erquinigo           return Error::success();
1636a5355e8SWalter Erquinigo         });
1646a5355e8SWalter Erquinigo     if (err)
1656a5355e8SWalter Erquinigo       return std::move(err);
166d30fd5c3SGaurav Gaur 
167e17cae07SWalter Erquinigo     m_unattributed_psb_blocks += psb_blocks->end() - it;
1686a5355e8SWalter Erquinigo   }
1696a5355e8SWalter Erquinigo   // We now sort the executions of each thread to have them ready for
1706a5355e8SWalter Erquinigo   // instruction decoding
1716a5355e8SWalter Erquinigo   for (auto &tid_executions : continuous_executions_per_thread)
1726a5355e8SWalter Erquinigo     std::sort(tid_executions.second.begin(), tid_executions.second.end());
1736a5355e8SWalter Erquinigo 
1746a5355e8SWalter Erquinigo   return continuous_executions_per_thread;
1756a5355e8SWalter Erquinigo }
1766a5355e8SWalter Erquinigo 
CorrelateContextSwitchesAndIntelPtTraces()1776a5355e8SWalter Erquinigo Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
1786a5355e8SWalter Erquinigo   if (m_setup_error)
1796a5355e8SWalter Erquinigo     return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
1806a5355e8SWalter Erquinigo 
1816a5355e8SWalter Erquinigo   if (m_continuous_executions_per_thread)
1826a5355e8SWalter Erquinigo     return Error::success();
1836a5355e8SWalter Erquinigo 
1849f9464e0SPeicong Wu   Error err = GetTrace()->GetGlobalTimer().TimeTask(
1856a5355e8SWalter Erquinigo       "Context switch and Intel PT traces correlation", [&]() -> Error {
1866a5355e8SWalter Erquinigo         if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) {
1876a5355e8SWalter Erquinigo           m_continuous_executions_per_thread.emplace(std::move(*correlation));
1886a5355e8SWalter Erquinigo           return Error::success();
1896a5355e8SWalter Erquinigo         } else {
1906a5355e8SWalter Erquinigo           return correlation.takeError();
1916a5355e8SWalter Erquinigo         }
1926a5355e8SWalter Erquinigo       });
1936a5355e8SWalter Erquinigo   if (err) {
1946a5355e8SWalter Erquinigo     m_setup_error = toString(std::move(err));
1956a5355e8SWalter Erquinigo     return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
1966a5355e8SWalter Erquinigo   }
1976a5355e8SWalter Erquinigo   return Error::success();
1986a5355e8SWalter Erquinigo }
1996a5355e8SWalter Erquinigo 
GetNumContinuousExecutionsForThread(lldb::tid_t tid) const2006a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread(
2016a5355e8SWalter Erquinigo     lldb::tid_t tid) const {
2026a5355e8SWalter Erquinigo   if (!m_continuous_executions_per_thread)
2036a5355e8SWalter Erquinigo     return 0;
2046a5355e8SWalter Erquinigo   auto it = m_continuous_executions_per_thread->find(tid);
2056a5355e8SWalter Erquinigo   if (it == m_continuous_executions_per_thread->end())
2066a5355e8SWalter Erquinigo     return 0;
2076a5355e8SWalter Erquinigo   return it->second.size();
2086a5355e8SWalter Erquinigo }
2096a5355e8SWalter Erquinigo 
GetTotalContinuousExecutionsCount() const2106a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const {
2116a5355e8SWalter Erquinigo   if (!m_continuous_executions_per_thread)
2126a5355e8SWalter Erquinigo     return 0;
2136a5355e8SWalter Erquinigo   size_t count = 0;
2146a5355e8SWalter Erquinigo   for (const auto &kv : *m_continuous_executions_per_thread)
2156a5355e8SWalter Erquinigo     count += kv.second.size();
2166a5355e8SWalter Erquinigo   return count;
2176a5355e8SWalter Erquinigo }
218d30fd5c3SGaurav Gaur 
219d30fd5c3SGaurav Gaur size_t
GePSBBlocksCountForThread(lldb::tid_t tid) const220d30fd5c3SGaurav Gaur TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const {
221d30fd5c3SGaurav Gaur   if (!m_continuous_executions_per_thread)
222d30fd5c3SGaurav Gaur     return 0;
223d30fd5c3SGaurav Gaur   size_t count = 0;
224d30fd5c3SGaurav Gaur   auto it = m_continuous_executions_per_thread->find(tid);
2250466d1dfSymeng   if (it == m_continuous_executions_per_thread->end())
2260466d1dfSymeng     return 0;
227d30fd5c3SGaurav Gaur   for (const IntelPTThreadContinousExecution &execution : it->second)
228e17cae07SWalter Erquinigo     count += execution.psb_blocks.size();
229d30fd5c3SGaurav Gaur   return count;
230d30fd5c3SGaurav Gaur }
231d30fd5c3SGaurav Gaur 
GetUnattributedPSBBlocksCount() const232d30fd5c3SGaurav Gaur size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const {
233d30fd5c3SGaurav Gaur   return m_unattributed_psb_blocks;
234d30fd5c3SGaurav Gaur }
235d30fd5c3SGaurav Gaur 
GetTotalPSBBlocksCount() const236d30fd5c3SGaurav Gaur size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const {
237d30fd5c3SGaurav Gaur   return m_total_psb_blocks;
238d30fd5c3SGaurav Gaur }
239