xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1753f127fSDimitry Andric //===-- TraceIntelPTMultiCpuDecoder.cpp -----------------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
981ad6265SDimitry Andric #include "TraceIntelPTMultiCpuDecoder.h"
1081ad6265SDimitry Andric #include "TraceIntelPT.h"
1181ad6265SDimitry Andric #include "llvm/Support/Error.h"
12*bdd1243dSDimitry Andric #include <optional>
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric using namespace lldb;
1581ad6265SDimitry Andric using namespace lldb_private;
1681ad6265SDimitry Andric using namespace lldb_private::trace_intel_pt;
1781ad6265SDimitry Andric using namespace llvm;
1881ad6265SDimitry Andric 
TraceIntelPTMultiCpuDecoder(TraceIntelPTSP trace_sp)1981ad6265SDimitry Andric TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder(
2081ad6265SDimitry Andric     TraceIntelPTSP trace_sp)
2181ad6265SDimitry Andric     : m_trace_wp(trace_sp) {
2281ad6265SDimitry Andric   for (Process *proc : trace_sp->GetAllProcesses()) {
2381ad6265SDimitry Andric     for (ThreadSP thread_sp : proc->GetThreadList().Threads()) {
2481ad6265SDimitry Andric       m_tids.insert(thread_sp->GetID());
2581ad6265SDimitry Andric     }
2681ad6265SDimitry Andric   }
2781ad6265SDimitry Andric }
2881ad6265SDimitry Andric 
GetTrace()2981ad6265SDimitry Andric TraceIntelPTSP TraceIntelPTMultiCpuDecoder::GetTrace() {
3081ad6265SDimitry Andric   return m_trace_wp.lock();
3181ad6265SDimitry Andric }
3281ad6265SDimitry Andric 
TracesThread(lldb::tid_t tid) const3381ad6265SDimitry Andric bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const {
3481ad6265SDimitry Andric   return m_tids.count(tid);
3581ad6265SDimitry Andric }
3681ad6265SDimitry Andric 
FindLowestTSC()37*bdd1243dSDimitry Andric Expected<std::optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() {
38*bdd1243dSDimitry Andric   std::optional<uint64_t> lowest_tsc;
39972a253aSDimitry Andric   TraceIntelPTSP trace_sp = GetTrace();
40972a253aSDimitry Andric 
41972a253aSDimitry Andric   Error err = GetTrace()->OnAllCpusBinaryDataRead(
42972a253aSDimitry Andric       IntelPTDataKinds::kIptTrace,
43972a253aSDimitry Andric       [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
44972a253aSDimitry Andric         for (auto &cpu_id_to_buffer : buffers) {
45*bdd1243dSDimitry Andric           Expected<std::optional<uint64_t>> tsc =
46972a253aSDimitry Andric               FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second);
47972a253aSDimitry Andric           if (!tsc)
48972a253aSDimitry Andric             return tsc.takeError();
49972a253aSDimitry Andric           if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
50972a253aSDimitry Andric             lowest_tsc = **tsc;
51972a253aSDimitry Andric         }
52972a253aSDimitry Andric         return Error::success();
53972a253aSDimitry Andric       });
54972a253aSDimitry Andric   if (err)
55972a253aSDimitry Andric     return std::move(err);
56972a253aSDimitry Andric   return lowest_tsc;
57972a253aSDimitry Andric }
58972a253aSDimitry Andric 
Decode(Thread & thread)5981ad6265SDimitry Andric Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
6081ad6265SDimitry Andric   if (Error err = CorrelateContextSwitchesAndIntelPtTraces())
6181ad6265SDimitry Andric     return std::move(err);
6281ad6265SDimitry Andric 
63753f127fSDimitry Andric   TraceIntelPTSP trace_sp = GetTrace();
64753f127fSDimitry Andric 
65*bdd1243dSDimitry Andric   return trace_sp->GetThreadTimer(thread.GetID())
66753f127fSDimitry Andric       .TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> {
6781ad6265SDimitry Andric         auto it = m_decoded_threads.find(thread.GetID());
6881ad6265SDimitry Andric         if (it != m_decoded_threads.end())
6981ad6265SDimitry Andric           return it->second;
7081ad6265SDimitry Andric 
71972a253aSDimitry Andric         DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(
72972a253aSDimitry Andric             thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion());
7381ad6265SDimitry Andric 
7481ad6265SDimitry Andric         Error err = trace_sp->OnAllCpusBinaryDataRead(
7581ad6265SDimitry Andric             IntelPTDataKinds::kIptTrace,
7681ad6265SDimitry Andric             [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
77753f127fSDimitry Andric               auto it =
78753f127fSDimitry Andric                   m_continuous_executions_per_thread->find(thread.GetID());
7981ad6265SDimitry Andric               if (it != m_continuous_executions_per_thread->end())
80753f127fSDimitry Andric                 return DecodeSystemWideTraceForThread(
81753f127fSDimitry Andric                     *decoded_thread_sp, *trace_sp, buffers, it->second);
8281ad6265SDimitry Andric 
8381ad6265SDimitry Andric               return Error::success();
8481ad6265SDimitry Andric             });
8581ad6265SDimitry Andric         if (err)
8681ad6265SDimitry Andric           return std::move(err);
8781ad6265SDimitry Andric 
8881ad6265SDimitry Andric         m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp);
8981ad6265SDimitry Andric         return decoded_thread_sp;
90753f127fSDimitry Andric       });
9181ad6265SDimitry Andric }
9281ad6265SDimitry Andric 
GetPSBBlocksForCPU(TraceIntelPT & trace,cpu_id_t cpu_id)93*bdd1243dSDimitry Andric static Expected<std::vector<PSBBlock>> GetPSBBlocksForCPU(TraceIntelPT &trace,
94*bdd1243dSDimitry Andric                                                           cpu_id_t cpu_id) {
95*bdd1243dSDimitry Andric   std::vector<PSBBlock> psb_blocks;
9681ad6265SDimitry Andric   Error err = trace.OnCpuBinaryDataRead(
9781ad6265SDimitry Andric       cpu_id, IntelPTDataKinds::kIptTrace,
9881ad6265SDimitry Andric       [&](ArrayRef<uint8_t> data) -> Error {
99*bdd1243dSDimitry Andric         Expected<std::vector<PSBBlock>> split_trace =
100*bdd1243dSDimitry Andric             SplitTraceIntoPSBBlock(trace, data, /*expect_tscs=*/true);
10181ad6265SDimitry Andric         if (!split_trace)
10281ad6265SDimitry Andric           return split_trace.takeError();
10381ad6265SDimitry Andric 
104*bdd1243dSDimitry Andric         psb_blocks = std::move(*split_trace);
10581ad6265SDimitry Andric         return Error::success();
10681ad6265SDimitry Andric       });
10781ad6265SDimitry Andric   if (err)
10881ad6265SDimitry Andric     return std::move(err);
109*bdd1243dSDimitry Andric   return psb_blocks;
11081ad6265SDimitry Andric }
11181ad6265SDimitry Andric 
11281ad6265SDimitry Andric Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
DoCorrelateContextSwitchesAndIntelPtTraces()11381ad6265SDimitry Andric TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {
11481ad6265SDimitry Andric   DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>
11581ad6265SDimitry Andric       continuous_executions_per_thread;
11681ad6265SDimitry Andric   TraceIntelPTSP trace_sp = GetTrace();
11781ad6265SDimitry Andric 
118*bdd1243dSDimitry Andric   std::optional<LinuxPerfZeroTscConversion> conv_opt =
11981ad6265SDimitry Andric       trace_sp->GetPerfZeroTscConversion();
12081ad6265SDimitry Andric   if (!conv_opt)
12181ad6265SDimitry Andric     return createStringError(
12281ad6265SDimitry Andric         inconvertibleErrorCode(),
12381ad6265SDimitry Andric         "TSC to nanoseconds conversion values were not found");
12481ad6265SDimitry Andric 
12581ad6265SDimitry Andric   LinuxPerfZeroTscConversion tsc_conversion = *conv_opt;
12681ad6265SDimitry Andric 
12781ad6265SDimitry Andric   for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) {
128*bdd1243dSDimitry Andric     Expected<std::vector<PSBBlock>> psb_blocks =
129*bdd1243dSDimitry Andric         GetPSBBlocksForCPU(*trace_sp, cpu_id);
130*bdd1243dSDimitry Andric     if (!psb_blocks)
131*bdd1243dSDimitry Andric       return psb_blocks.takeError();
13281ad6265SDimitry Andric 
133*bdd1243dSDimitry Andric     m_total_psb_blocks += psb_blocks->size();
13481ad6265SDimitry Andric     // We'll be iterating through the thread continuous executions and the intel
13581ad6265SDimitry Andric     // pt subtraces sorted by time.
136*bdd1243dSDimitry Andric     auto it = psb_blocks->begin();
13781ad6265SDimitry Andric     auto on_new_thread_execution =
13881ad6265SDimitry Andric         [&](const ThreadContinuousExecution &thread_execution) {
13981ad6265SDimitry Andric           IntelPTThreadContinousExecution execution(thread_execution);
14081ad6265SDimitry Andric 
141*bdd1243dSDimitry Andric           for (; it != psb_blocks->end() &&
142*bdd1243dSDimitry Andric                  *it->tsc < thread_execution.GetEndTSC();
14381ad6265SDimitry Andric                it++) {
144*bdd1243dSDimitry Andric             if (*it->tsc > thread_execution.GetStartTSC()) {
145*bdd1243dSDimitry Andric               execution.psb_blocks.push_back(*it);
14681ad6265SDimitry Andric             } else {
147753f127fSDimitry Andric               m_unattributed_psb_blocks++;
14881ad6265SDimitry Andric             }
14981ad6265SDimitry Andric           }
15081ad6265SDimitry Andric           continuous_executions_per_thread[thread_execution.tid].push_back(
15181ad6265SDimitry Andric               execution);
15281ad6265SDimitry Andric         };
15381ad6265SDimitry Andric     Error err = trace_sp->OnCpuBinaryDataRead(
15481ad6265SDimitry Andric         cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,
15581ad6265SDimitry Andric         [&](ArrayRef<uint8_t> data) -> Error {
15681ad6265SDimitry Andric           Expected<std::vector<ThreadContinuousExecution>> executions =
15781ad6265SDimitry Andric               DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion);
15881ad6265SDimitry Andric           if (!executions)
15981ad6265SDimitry Andric             return executions.takeError();
16081ad6265SDimitry Andric           for (const ThreadContinuousExecution &exec : *executions)
16181ad6265SDimitry Andric             on_new_thread_execution(exec);
16281ad6265SDimitry Andric           return Error::success();
16381ad6265SDimitry Andric         });
16481ad6265SDimitry Andric     if (err)
16581ad6265SDimitry Andric       return std::move(err);
166753f127fSDimitry Andric 
167*bdd1243dSDimitry Andric     m_unattributed_psb_blocks += psb_blocks->end() - it;
16881ad6265SDimitry Andric   }
16981ad6265SDimitry Andric   // We now sort the executions of each thread to have them ready for
17081ad6265SDimitry Andric   // instruction decoding
17181ad6265SDimitry Andric   for (auto &tid_executions : continuous_executions_per_thread)
17281ad6265SDimitry Andric     std::sort(tid_executions.second.begin(), tid_executions.second.end());
17381ad6265SDimitry Andric 
17481ad6265SDimitry Andric   return continuous_executions_per_thread;
17581ad6265SDimitry Andric }
17681ad6265SDimitry Andric 
CorrelateContextSwitchesAndIntelPtTraces()17781ad6265SDimitry Andric Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
17881ad6265SDimitry Andric   if (m_setup_error)
17981ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
18081ad6265SDimitry Andric 
18181ad6265SDimitry Andric   if (m_continuous_executions_per_thread)
18281ad6265SDimitry Andric     return Error::success();
18381ad6265SDimitry Andric 
184753f127fSDimitry Andric   Error err = GetTrace()->GetGlobalTimer().TimeTask(
18581ad6265SDimitry Andric       "Context switch and Intel PT traces correlation", [&]() -> Error {
18681ad6265SDimitry Andric         if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) {
18781ad6265SDimitry Andric           m_continuous_executions_per_thread.emplace(std::move(*correlation));
18881ad6265SDimitry Andric           return Error::success();
18981ad6265SDimitry Andric         } else {
19081ad6265SDimitry Andric           return correlation.takeError();
19181ad6265SDimitry Andric         }
19281ad6265SDimitry Andric       });
19381ad6265SDimitry Andric   if (err) {
19481ad6265SDimitry Andric     m_setup_error = toString(std::move(err));
19581ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
19681ad6265SDimitry Andric   }
19781ad6265SDimitry Andric   return Error::success();
19881ad6265SDimitry Andric }
19981ad6265SDimitry Andric 
GetNumContinuousExecutionsForThread(lldb::tid_t tid) const20081ad6265SDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread(
20181ad6265SDimitry Andric     lldb::tid_t tid) const {
20281ad6265SDimitry Andric   if (!m_continuous_executions_per_thread)
20381ad6265SDimitry Andric     return 0;
20481ad6265SDimitry Andric   auto it = m_continuous_executions_per_thread->find(tid);
20581ad6265SDimitry Andric   if (it == m_continuous_executions_per_thread->end())
20681ad6265SDimitry Andric     return 0;
20781ad6265SDimitry Andric   return it->second.size();
20881ad6265SDimitry Andric }
20981ad6265SDimitry Andric 
GetTotalContinuousExecutionsCount() const21081ad6265SDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const {
21181ad6265SDimitry Andric   if (!m_continuous_executions_per_thread)
21281ad6265SDimitry Andric     return 0;
21381ad6265SDimitry Andric   size_t count = 0;
21481ad6265SDimitry Andric   for (const auto &kv : *m_continuous_executions_per_thread)
21581ad6265SDimitry Andric     count += kv.second.size();
21681ad6265SDimitry Andric   return count;
21781ad6265SDimitry Andric }
218753f127fSDimitry Andric 
219753f127fSDimitry Andric size_t
GePSBBlocksCountForThread(lldb::tid_t tid) const220753f127fSDimitry Andric TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const {
221753f127fSDimitry Andric   if (!m_continuous_executions_per_thread)
222753f127fSDimitry Andric     return 0;
223753f127fSDimitry Andric   size_t count = 0;
224753f127fSDimitry Andric   auto it = m_continuous_executions_per_thread->find(tid);
225753f127fSDimitry Andric   if (it == m_continuous_executions_per_thread->end())
226753f127fSDimitry Andric     return 0;
227753f127fSDimitry Andric   for (const IntelPTThreadContinousExecution &execution : it->second)
228*bdd1243dSDimitry Andric     count += execution.psb_blocks.size();
229753f127fSDimitry Andric   return count;
230753f127fSDimitry Andric }
231753f127fSDimitry Andric 
GetUnattributedPSBBlocksCount() const232753f127fSDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const {
233753f127fSDimitry Andric   return m_unattributed_psb_blocks;
234753f127fSDimitry Andric }
235753f127fSDimitry Andric 
GetTotalPSBBlocksCount() const236753f127fSDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const {
237753f127fSDimitry Andric   return m_total_psb_blocks;
238753f127fSDimitry Andric }
239