xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp (revision 972a253a57b6f144b0e4a3e2080a2a0076ec55a0)
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 
1181ad6265SDimitry Andric #include "TraceIntelPT.h"
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #include "llvm/Support/Error.h"
1481ad6265SDimitry Andric 
1581ad6265SDimitry Andric using namespace lldb;
1681ad6265SDimitry Andric using namespace lldb_private;
1781ad6265SDimitry Andric using namespace lldb_private::trace_intel_pt;
1881ad6265SDimitry Andric using namespace llvm;
1981ad6265SDimitry Andric 
2081ad6265SDimitry Andric TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder(
2181ad6265SDimitry Andric     TraceIntelPTSP trace_sp)
2281ad6265SDimitry Andric     : m_trace_wp(trace_sp) {
2381ad6265SDimitry Andric   for (Process *proc : trace_sp->GetAllProcesses()) {
2481ad6265SDimitry Andric     for (ThreadSP thread_sp : proc->GetThreadList().Threads()) {
2581ad6265SDimitry Andric       m_tids.insert(thread_sp->GetID());
2681ad6265SDimitry Andric     }
2781ad6265SDimitry Andric   }
2881ad6265SDimitry Andric }
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric TraceIntelPTSP TraceIntelPTMultiCpuDecoder::GetTrace() {
3181ad6265SDimitry Andric   return m_trace_wp.lock();
3281ad6265SDimitry Andric }
3381ad6265SDimitry Andric 
3481ad6265SDimitry Andric bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const {
3581ad6265SDimitry Andric   return m_tids.count(tid);
3681ad6265SDimitry Andric }
3781ad6265SDimitry Andric 
38*972a253aSDimitry Andric Expected<Optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() {
39*972a253aSDimitry Andric   Optional<uint64_t> lowest_tsc;
40*972a253aSDimitry Andric   TraceIntelPTSP trace_sp = GetTrace();
41*972a253aSDimitry Andric 
42*972a253aSDimitry Andric   Error err = GetTrace()->OnAllCpusBinaryDataRead(
43*972a253aSDimitry Andric       IntelPTDataKinds::kIptTrace,
44*972a253aSDimitry Andric       [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
45*972a253aSDimitry Andric         for (auto &cpu_id_to_buffer : buffers) {
46*972a253aSDimitry Andric           Expected<Optional<uint64_t>> tsc =
47*972a253aSDimitry Andric               FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second);
48*972a253aSDimitry Andric           if (!tsc)
49*972a253aSDimitry Andric             return tsc.takeError();
50*972a253aSDimitry Andric           if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
51*972a253aSDimitry Andric             lowest_tsc = **tsc;
52*972a253aSDimitry Andric         }
53*972a253aSDimitry Andric         return Error::success();
54*972a253aSDimitry Andric       });
55*972a253aSDimitry Andric   if (err)
56*972a253aSDimitry Andric     return std::move(err);
57*972a253aSDimitry Andric   return lowest_tsc;
58*972a253aSDimitry Andric }
59*972a253aSDimitry Andric 
6081ad6265SDimitry Andric Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
6181ad6265SDimitry Andric   if (Error err = CorrelateContextSwitchesAndIntelPtTraces())
6281ad6265SDimitry Andric     return std::move(err);
6381ad6265SDimitry Andric 
64753f127fSDimitry Andric   TraceIntelPTSP trace_sp = GetTrace();
65753f127fSDimitry Andric 
66753f127fSDimitry Andric   return trace_sp
67753f127fSDimitry Andric       ->GetThreadTimer(thread.GetID())
68753f127fSDimitry Andric       .TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> {
6981ad6265SDimitry Andric         auto it = m_decoded_threads.find(thread.GetID());
7081ad6265SDimitry Andric         if (it != m_decoded_threads.end())
7181ad6265SDimitry Andric           return it->second;
7281ad6265SDimitry Andric 
73*972a253aSDimitry Andric         DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(
74*972a253aSDimitry Andric             thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion());
7581ad6265SDimitry Andric 
7681ad6265SDimitry Andric         Error err = trace_sp->OnAllCpusBinaryDataRead(
7781ad6265SDimitry Andric             IntelPTDataKinds::kIptTrace,
7881ad6265SDimitry Andric             [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
79753f127fSDimitry Andric               auto it =
80753f127fSDimitry Andric                   m_continuous_executions_per_thread->find(thread.GetID());
8181ad6265SDimitry Andric               if (it != m_continuous_executions_per_thread->end())
82753f127fSDimitry Andric                 return DecodeSystemWideTraceForThread(
83753f127fSDimitry Andric                     *decoded_thread_sp, *trace_sp, buffers, it->second);
8481ad6265SDimitry Andric 
8581ad6265SDimitry Andric               return Error::success();
8681ad6265SDimitry Andric             });
8781ad6265SDimitry Andric         if (err)
8881ad6265SDimitry Andric           return std::move(err);
8981ad6265SDimitry Andric 
9081ad6265SDimitry Andric         m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp);
9181ad6265SDimitry Andric         return decoded_thread_sp;
92753f127fSDimitry Andric       });
9381ad6265SDimitry Andric }
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric static Expected<std::vector<IntelPTThreadSubtrace>>
9681ad6265SDimitry Andric GetIntelPTSubtracesForCpu(TraceIntelPT &trace, cpu_id_t cpu_id) {
9781ad6265SDimitry Andric   std::vector<IntelPTThreadSubtrace> intel_pt_subtraces;
9881ad6265SDimitry Andric   Error err = trace.OnCpuBinaryDataRead(
9981ad6265SDimitry Andric       cpu_id, IntelPTDataKinds::kIptTrace,
10081ad6265SDimitry Andric       [&](ArrayRef<uint8_t> data) -> Error {
10181ad6265SDimitry Andric         Expected<std::vector<IntelPTThreadSubtrace>> split_trace =
10281ad6265SDimitry Andric             SplitTraceInContinuousExecutions(trace, data);
10381ad6265SDimitry Andric         if (!split_trace)
10481ad6265SDimitry Andric           return split_trace.takeError();
10581ad6265SDimitry Andric 
10681ad6265SDimitry Andric         intel_pt_subtraces = std::move(*split_trace);
10781ad6265SDimitry Andric         return Error::success();
10881ad6265SDimitry Andric       });
10981ad6265SDimitry Andric   if (err)
11081ad6265SDimitry Andric     return std::move(err);
11181ad6265SDimitry Andric   return intel_pt_subtraces;
11281ad6265SDimitry Andric }
11381ad6265SDimitry Andric 
11481ad6265SDimitry Andric Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
11581ad6265SDimitry Andric TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {
11681ad6265SDimitry Andric   DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>
11781ad6265SDimitry Andric       continuous_executions_per_thread;
11881ad6265SDimitry Andric   TraceIntelPTSP trace_sp = GetTrace();
11981ad6265SDimitry Andric 
12081ad6265SDimitry Andric   Optional<LinuxPerfZeroTscConversion> conv_opt =
12181ad6265SDimitry Andric       trace_sp->GetPerfZeroTscConversion();
12281ad6265SDimitry Andric   if (!conv_opt)
12381ad6265SDimitry Andric     return createStringError(
12481ad6265SDimitry Andric         inconvertibleErrorCode(),
12581ad6265SDimitry Andric         "TSC to nanoseconds conversion values were not found");
12681ad6265SDimitry Andric 
12781ad6265SDimitry Andric   LinuxPerfZeroTscConversion tsc_conversion = *conv_opt;
12881ad6265SDimitry Andric 
12981ad6265SDimitry Andric   for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) {
13081ad6265SDimitry Andric     Expected<std::vector<IntelPTThreadSubtrace>> intel_pt_subtraces =
13181ad6265SDimitry Andric         GetIntelPTSubtracesForCpu(*trace_sp, cpu_id);
13281ad6265SDimitry Andric     if (!intel_pt_subtraces)
13381ad6265SDimitry Andric       return intel_pt_subtraces.takeError();
13481ad6265SDimitry Andric 
135753f127fSDimitry Andric     m_total_psb_blocks += intel_pt_subtraces->size();
13681ad6265SDimitry Andric     // We'll be iterating through the thread continuous executions and the intel
13781ad6265SDimitry Andric     // pt subtraces sorted by time.
13881ad6265SDimitry Andric     auto it = intel_pt_subtraces->begin();
13981ad6265SDimitry Andric     auto on_new_thread_execution =
14081ad6265SDimitry Andric         [&](const ThreadContinuousExecution &thread_execution) {
14181ad6265SDimitry Andric           IntelPTThreadContinousExecution execution(thread_execution);
14281ad6265SDimitry Andric 
14381ad6265SDimitry Andric           for (; it != intel_pt_subtraces->end() &&
14481ad6265SDimitry Andric                  it->tsc < thread_execution.GetEndTSC();
14581ad6265SDimitry Andric                it++) {
14681ad6265SDimitry Andric             if (it->tsc > thread_execution.GetStartTSC()) {
14781ad6265SDimitry Andric               execution.intelpt_subtraces.push_back(*it);
14881ad6265SDimitry Andric             } else {
149753f127fSDimitry Andric               m_unattributed_psb_blocks++;
15081ad6265SDimitry Andric             }
15181ad6265SDimitry Andric           }
15281ad6265SDimitry Andric           continuous_executions_per_thread[thread_execution.tid].push_back(
15381ad6265SDimitry Andric               execution);
15481ad6265SDimitry Andric         };
15581ad6265SDimitry Andric     Error err = trace_sp->OnCpuBinaryDataRead(
15681ad6265SDimitry Andric         cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,
15781ad6265SDimitry Andric         [&](ArrayRef<uint8_t> data) -> Error {
15881ad6265SDimitry Andric           Expected<std::vector<ThreadContinuousExecution>> executions =
15981ad6265SDimitry Andric               DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion);
16081ad6265SDimitry Andric           if (!executions)
16181ad6265SDimitry Andric             return executions.takeError();
16281ad6265SDimitry Andric           for (const ThreadContinuousExecution &exec : *executions)
16381ad6265SDimitry Andric             on_new_thread_execution(exec);
16481ad6265SDimitry Andric           return Error::success();
16581ad6265SDimitry Andric         });
16681ad6265SDimitry Andric     if (err)
16781ad6265SDimitry Andric       return std::move(err);
168753f127fSDimitry Andric 
169753f127fSDimitry Andric     m_unattributed_psb_blocks += intel_pt_subtraces->end() - it;
17081ad6265SDimitry Andric   }
17181ad6265SDimitry Andric   // We now sort the executions of each thread to have them ready for
17281ad6265SDimitry Andric   // instruction decoding
17381ad6265SDimitry Andric   for (auto &tid_executions : continuous_executions_per_thread)
17481ad6265SDimitry Andric     std::sort(tid_executions.second.begin(), tid_executions.second.end());
17581ad6265SDimitry Andric 
17681ad6265SDimitry Andric   return continuous_executions_per_thread;
17781ad6265SDimitry Andric }
17881ad6265SDimitry Andric 
17981ad6265SDimitry Andric Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
18081ad6265SDimitry Andric   if (m_setup_error)
18181ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
18281ad6265SDimitry Andric 
18381ad6265SDimitry Andric   if (m_continuous_executions_per_thread)
18481ad6265SDimitry Andric     return Error::success();
18581ad6265SDimitry Andric 
186753f127fSDimitry Andric   Error err = GetTrace()->GetGlobalTimer().TimeTask(
18781ad6265SDimitry Andric       "Context switch and Intel PT traces correlation", [&]() -> Error {
18881ad6265SDimitry Andric         if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) {
18981ad6265SDimitry Andric           m_continuous_executions_per_thread.emplace(std::move(*correlation));
19081ad6265SDimitry Andric           return Error::success();
19181ad6265SDimitry Andric         } else {
19281ad6265SDimitry Andric           return correlation.takeError();
19381ad6265SDimitry Andric         }
19481ad6265SDimitry Andric       });
19581ad6265SDimitry Andric   if (err) {
19681ad6265SDimitry Andric     m_setup_error = toString(std::move(err));
19781ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
19881ad6265SDimitry Andric   }
19981ad6265SDimitry Andric   return Error::success();
20081ad6265SDimitry Andric }
20181ad6265SDimitry Andric 
20281ad6265SDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread(
20381ad6265SDimitry Andric     lldb::tid_t tid) const {
20481ad6265SDimitry Andric   if (!m_continuous_executions_per_thread)
20581ad6265SDimitry Andric     return 0;
20681ad6265SDimitry Andric   auto it = m_continuous_executions_per_thread->find(tid);
20781ad6265SDimitry Andric   if (it == m_continuous_executions_per_thread->end())
20881ad6265SDimitry Andric     return 0;
20981ad6265SDimitry Andric   return it->second.size();
21081ad6265SDimitry Andric }
21181ad6265SDimitry Andric 
21281ad6265SDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const {
21381ad6265SDimitry Andric   if (!m_continuous_executions_per_thread)
21481ad6265SDimitry Andric     return 0;
21581ad6265SDimitry Andric   size_t count = 0;
21681ad6265SDimitry Andric   for (const auto &kv : *m_continuous_executions_per_thread)
21781ad6265SDimitry Andric     count += kv.second.size();
21881ad6265SDimitry Andric   return count;
21981ad6265SDimitry Andric }
220753f127fSDimitry Andric 
221753f127fSDimitry Andric size_t
222753f127fSDimitry Andric TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const {
223753f127fSDimitry Andric   if (!m_continuous_executions_per_thread)
224753f127fSDimitry Andric     return 0;
225753f127fSDimitry Andric   size_t count = 0;
226753f127fSDimitry Andric   auto it = m_continuous_executions_per_thread->find(tid);
227753f127fSDimitry Andric   if (it == m_continuous_executions_per_thread->end())
228753f127fSDimitry Andric     return 0;
229753f127fSDimitry Andric   for (const IntelPTThreadContinousExecution &execution : it->second)
230753f127fSDimitry Andric     count += execution.intelpt_subtraces.size();
231753f127fSDimitry Andric   return count;
232753f127fSDimitry Andric }
233753f127fSDimitry Andric 
234753f127fSDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const {
235753f127fSDimitry Andric   return m_unattributed_psb_blocks;
236753f127fSDimitry Andric }
237753f127fSDimitry Andric 
238753f127fSDimitry Andric size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const {
239753f127fSDimitry Andric   return m_total_psb_blocks;
240753f127fSDimitry Andric }
241