1*6a5355e8SWalter Erquinigo //===-- TraceIntelPTMultiCpuDecoder.cpp ----0------------------------------===//
2*6a5355e8SWalter Erquinigo //
3*6a5355e8SWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*6a5355e8SWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information.
5*6a5355e8SWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*6a5355e8SWalter Erquinigo //
7*6a5355e8SWalter Erquinigo //===----------------------------------------------------------------------===//
8*6a5355e8SWalter Erquinigo 
9*6a5355e8SWalter Erquinigo #include "TraceIntelPTMultiCpuDecoder.h"
10*6a5355e8SWalter Erquinigo 
11*6a5355e8SWalter Erquinigo #include "TraceIntelPT.h"
12*6a5355e8SWalter Erquinigo 
13*6a5355e8SWalter Erquinigo #include "llvm/Support/Error.h"
14*6a5355e8SWalter Erquinigo 
15*6a5355e8SWalter Erquinigo using namespace lldb;
16*6a5355e8SWalter Erquinigo using namespace lldb_private;
17*6a5355e8SWalter Erquinigo using namespace lldb_private::trace_intel_pt;
18*6a5355e8SWalter Erquinigo using namespace llvm;
19*6a5355e8SWalter Erquinigo 
20*6a5355e8SWalter Erquinigo TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder(TraceIntelPT &trace)
21*6a5355e8SWalter Erquinigo     : m_trace(&trace) {
22*6a5355e8SWalter Erquinigo   for (Process *proc : trace.GetAllProcesses()) {
23*6a5355e8SWalter Erquinigo     for (ThreadSP thread_sp : proc->GetThreadList().Threads()) {
24*6a5355e8SWalter Erquinigo       m_tids.insert(thread_sp->GetID());
25*6a5355e8SWalter Erquinigo     }
26*6a5355e8SWalter Erquinigo   }
27*6a5355e8SWalter Erquinigo }
28*6a5355e8SWalter Erquinigo 
29*6a5355e8SWalter Erquinigo bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const {
30*6a5355e8SWalter Erquinigo   return m_tids.count(tid);
31*6a5355e8SWalter Erquinigo }
32*6a5355e8SWalter Erquinigo 
33*6a5355e8SWalter Erquinigo DecodedThreadSP TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
34*6a5355e8SWalter Erquinigo   if (Error err = CorrelateContextSwitchesAndIntelPtTraces())
35*6a5355e8SWalter Erquinigo     return std::make_shared<DecodedThread>(thread.shared_from_this(),
36*6a5355e8SWalter Erquinigo                                            std::move(err));
37*6a5355e8SWalter Erquinigo   auto it = m_decoded_threads.find(thread.GetID());
38*6a5355e8SWalter Erquinigo   if (it != m_decoded_threads.end())
39*6a5355e8SWalter Erquinigo     return it->second;
40*6a5355e8SWalter Erquinigo 
41*6a5355e8SWalter Erquinigo   DecodedThreadSP decoded_thread_sp =
42*6a5355e8SWalter Erquinigo       std::make_shared<DecodedThread>(thread.shared_from_this());
43*6a5355e8SWalter Erquinigo 
44*6a5355e8SWalter Erquinigo   Error err = m_trace->OnAllCpusBinaryDataRead(
45*6a5355e8SWalter Erquinigo       IntelPTDataKinds::kIptTrace,
46*6a5355e8SWalter Erquinigo       [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
47*6a5355e8SWalter Erquinigo         auto it = m_continuous_executions_per_thread->find(thread.GetID());
48*6a5355e8SWalter Erquinigo         if (it != m_continuous_executions_per_thread->end())
49*6a5355e8SWalter Erquinigo           DecodeSystemWideTraceForThread(*decoded_thread_sp, *m_trace, buffers,
50*6a5355e8SWalter Erquinigo                                          it->second);
51*6a5355e8SWalter Erquinigo 
52*6a5355e8SWalter Erquinigo         return Error::success();
53*6a5355e8SWalter Erquinigo       });
54*6a5355e8SWalter Erquinigo   if (err)
55*6a5355e8SWalter Erquinigo     decoded_thread_sp->SetAsFailed(std::move(err));
56*6a5355e8SWalter Erquinigo 
57*6a5355e8SWalter Erquinigo   m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp);
58*6a5355e8SWalter Erquinigo   return decoded_thread_sp;
59*6a5355e8SWalter Erquinigo }
60*6a5355e8SWalter Erquinigo 
61*6a5355e8SWalter Erquinigo static Expected<std::vector<IntelPTThreadSubtrace>>
62*6a5355e8SWalter Erquinigo GetIntelPTSubtracesForCpu(TraceIntelPT &trace, cpu_id_t cpu_id) {
63*6a5355e8SWalter Erquinigo   std::vector<IntelPTThreadSubtrace> intel_pt_subtraces;
64*6a5355e8SWalter Erquinigo   Error err = trace.OnCpuBinaryDataRead(
65*6a5355e8SWalter Erquinigo       cpu_id, IntelPTDataKinds::kIptTrace,
66*6a5355e8SWalter Erquinigo       [&](ArrayRef<uint8_t> data) -> Error {
67*6a5355e8SWalter Erquinigo         Expected<std::vector<IntelPTThreadSubtrace>> split_trace =
68*6a5355e8SWalter Erquinigo             SplitTraceInContinuousExecutions(trace, data);
69*6a5355e8SWalter Erquinigo         if (!split_trace)
70*6a5355e8SWalter Erquinigo           return split_trace.takeError();
71*6a5355e8SWalter Erquinigo 
72*6a5355e8SWalter Erquinigo         intel_pt_subtraces = std::move(*split_trace);
73*6a5355e8SWalter Erquinigo         return Error::success();
74*6a5355e8SWalter Erquinigo       });
75*6a5355e8SWalter Erquinigo   if (err)
76*6a5355e8SWalter Erquinigo     return std::move(err);
77*6a5355e8SWalter Erquinigo   return intel_pt_subtraces;
78*6a5355e8SWalter Erquinigo }
79*6a5355e8SWalter Erquinigo 
80*6a5355e8SWalter Erquinigo Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
81*6a5355e8SWalter Erquinigo TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {
82*6a5355e8SWalter Erquinigo   DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>
83*6a5355e8SWalter Erquinigo       continuous_executions_per_thread;
84*6a5355e8SWalter Erquinigo 
85*6a5355e8SWalter Erquinigo   Optional<LinuxPerfZeroTscConversion> conv_opt =
86*6a5355e8SWalter Erquinigo       m_trace->GetPerfZeroTscConversion();
87*6a5355e8SWalter Erquinigo   if (!conv_opt)
88*6a5355e8SWalter Erquinigo     return createStringError(
89*6a5355e8SWalter Erquinigo         inconvertibleErrorCode(),
90*6a5355e8SWalter Erquinigo         "TSC to nanoseconds conversion values were not found");
91*6a5355e8SWalter Erquinigo 
92*6a5355e8SWalter Erquinigo   LinuxPerfZeroTscConversion tsc_conversion = *conv_opt;
93*6a5355e8SWalter Erquinigo 
94*6a5355e8SWalter Erquinigo   for (cpu_id_t cpu_id : m_trace->GetTracedCpus()) {
95*6a5355e8SWalter Erquinigo     Expected<std::vector<IntelPTThreadSubtrace>> intel_pt_subtraces =
96*6a5355e8SWalter Erquinigo         GetIntelPTSubtracesForCpu(*m_trace, cpu_id);
97*6a5355e8SWalter Erquinigo     if (!intel_pt_subtraces)
98*6a5355e8SWalter Erquinigo       return intel_pt_subtraces.takeError();
99*6a5355e8SWalter Erquinigo 
100*6a5355e8SWalter Erquinigo     // We'll be iterating through the thread continuous executions and the intel
101*6a5355e8SWalter Erquinigo     // pt subtraces sorted by time.
102*6a5355e8SWalter Erquinigo     auto it = intel_pt_subtraces->begin();
103*6a5355e8SWalter Erquinigo     auto on_new_thread_execution =
104*6a5355e8SWalter Erquinigo         [&](const ThreadContinuousExecution &thread_execution) {
105*6a5355e8SWalter Erquinigo           IntelPTThreadContinousExecution execution(thread_execution);
106*6a5355e8SWalter Erquinigo 
107*6a5355e8SWalter Erquinigo           for (; it != intel_pt_subtraces->end() &&
108*6a5355e8SWalter Erquinigo                  it->tsc < thread_execution.GetEndTSC();
109*6a5355e8SWalter Erquinigo                it++) {
110*6a5355e8SWalter Erquinigo             if (it->tsc > thread_execution.GetStartTSC()) {
111*6a5355e8SWalter Erquinigo               execution.intelpt_subtraces.push_back(*it);
112*6a5355e8SWalter Erquinigo             } else {
113*6a5355e8SWalter Erquinigo               m_unattributed_intelpt_subtraces++;
114*6a5355e8SWalter Erquinigo             }
115*6a5355e8SWalter Erquinigo           }
116*6a5355e8SWalter Erquinigo           continuous_executions_per_thread[thread_execution.tid].push_back(
117*6a5355e8SWalter Erquinigo               execution);
118*6a5355e8SWalter Erquinigo         };
119*6a5355e8SWalter Erquinigo     Error err = m_trace->OnCpuBinaryDataRead(
120*6a5355e8SWalter Erquinigo         cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,
121*6a5355e8SWalter Erquinigo         [&](ArrayRef<uint8_t> data) -> Error {
122*6a5355e8SWalter Erquinigo           Expected<std::vector<ThreadContinuousExecution>> executions =
123*6a5355e8SWalter Erquinigo               DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion);
124*6a5355e8SWalter Erquinigo           if (!executions)
125*6a5355e8SWalter Erquinigo             return executions.takeError();
126*6a5355e8SWalter Erquinigo           for (const ThreadContinuousExecution &exec : *executions)
127*6a5355e8SWalter Erquinigo             on_new_thread_execution(exec);
128*6a5355e8SWalter Erquinigo           return Error::success();
129*6a5355e8SWalter Erquinigo         });
130*6a5355e8SWalter Erquinigo     if (err)
131*6a5355e8SWalter Erquinigo       return std::move(err);
132*6a5355e8SWalter Erquinigo   }
133*6a5355e8SWalter Erquinigo   // We now sort the executions of each thread to have them ready for
134*6a5355e8SWalter Erquinigo   // instruction decoding
135*6a5355e8SWalter Erquinigo   for (auto &tid_executions : continuous_executions_per_thread)
136*6a5355e8SWalter Erquinigo     std::sort(tid_executions.second.begin(), tid_executions.second.end());
137*6a5355e8SWalter Erquinigo 
138*6a5355e8SWalter Erquinigo   return continuous_executions_per_thread;
139*6a5355e8SWalter Erquinigo }
140*6a5355e8SWalter Erquinigo 
141*6a5355e8SWalter Erquinigo Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
142*6a5355e8SWalter Erquinigo   if (m_setup_error)
143*6a5355e8SWalter Erquinigo     return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
144*6a5355e8SWalter Erquinigo 
145*6a5355e8SWalter Erquinigo   if (m_continuous_executions_per_thread)
146*6a5355e8SWalter Erquinigo     return Error::success();
147*6a5355e8SWalter Erquinigo 
148*6a5355e8SWalter Erquinigo   Error err = m_trace->GetTimer().ForGlobal().TimeTask<Error>(
149*6a5355e8SWalter Erquinigo       "Context switch and Intel PT traces correlation", [&]() -> Error {
150*6a5355e8SWalter Erquinigo         if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) {
151*6a5355e8SWalter Erquinigo           m_continuous_executions_per_thread.emplace(std::move(*correlation));
152*6a5355e8SWalter Erquinigo           return Error::success();
153*6a5355e8SWalter Erquinigo         } else {
154*6a5355e8SWalter Erquinigo           return correlation.takeError();
155*6a5355e8SWalter Erquinigo         }
156*6a5355e8SWalter Erquinigo       });
157*6a5355e8SWalter Erquinigo   if (err) {
158*6a5355e8SWalter Erquinigo     m_setup_error = toString(std::move(err));
159*6a5355e8SWalter Erquinigo     return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
160*6a5355e8SWalter Erquinigo   }
161*6a5355e8SWalter Erquinigo   return Error::success();
162*6a5355e8SWalter Erquinigo }
163*6a5355e8SWalter Erquinigo 
164*6a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread(
165*6a5355e8SWalter Erquinigo     lldb::tid_t tid) const {
166*6a5355e8SWalter Erquinigo   if (!m_continuous_executions_per_thread)
167*6a5355e8SWalter Erquinigo     return 0;
168*6a5355e8SWalter Erquinigo   auto it = m_continuous_executions_per_thread->find(tid);
169*6a5355e8SWalter Erquinigo   if (it == m_continuous_executions_per_thread->end())
170*6a5355e8SWalter Erquinigo     return 0;
171*6a5355e8SWalter Erquinigo   return it->second.size();
172*6a5355e8SWalter Erquinigo }
173*6a5355e8SWalter Erquinigo 
174*6a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const {
175*6a5355e8SWalter Erquinigo   if (!m_continuous_executions_per_thread)
176*6a5355e8SWalter Erquinigo     return 0;
177*6a5355e8SWalter Erquinigo   size_t count = 0;
178*6a5355e8SWalter Erquinigo   for (const auto &kv : *m_continuous_executions_per_thread)
179*6a5355e8SWalter Erquinigo     count += kv.second.size();
180*6a5355e8SWalter Erquinigo   return count;
181*6a5355e8SWalter Erquinigo }
182