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
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
TraceIntelPTMultiCpuDecoder(TraceIntelPTSP trace_sp)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
GetTrace()30ea37cd52SWalter Erquinigo TraceIntelPTSP TraceIntelPTMultiCpuDecoder::GetTrace() {
31ea37cd52SWalter Erquinigo return m_trace_wp.lock();
32ea37cd52SWalter Erquinigo }
33ea37cd52SWalter Erquinigo
TracesThread(lldb::tid_t tid) const346a5355e8SWalter Erquinigo bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const {
356a5355e8SWalter Erquinigo return m_tids.count(tid);
366a5355e8SWalter Erquinigo }
376a5355e8SWalter Erquinigo
FindLowestTSC()38*4f676c25SWalter Erquinigo Expected<Optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() {
39*4f676c25SWalter Erquinigo Optional<uint64_t> lowest_tsc;
40*4f676c25SWalter Erquinigo TraceIntelPTSP trace_sp = GetTrace();
41*4f676c25SWalter Erquinigo
42*4f676c25SWalter Erquinigo Error err = GetTrace()->OnAllCpusBinaryDataRead(
43*4f676c25SWalter Erquinigo IntelPTDataKinds::kIptTrace,
44*4f676c25SWalter Erquinigo [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
45*4f676c25SWalter Erquinigo for (auto &cpu_id_to_buffer : buffers) {
46*4f676c25SWalter Erquinigo Expected<Optional<uint64_t>> tsc =
47*4f676c25SWalter Erquinigo FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second);
48*4f676c25SWalter Erquinigo if (!tsc)
49*4f676c25SWalter Erquinigo return tsc.takeError();
50*4f676c25SWalter Erquinigo if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
51*4f676c25SWalter Erquinigo lowest_tsc = **tsc;
52*4f676c25SWalter Erquinigo }
53*4f676c25SWalter Erquinigo return Error::success();
54*4f676c25SWalter Erquinigo });
55*4f676c25SWalter Erquinigo if (err)
56*4f676c25SWalter Erquinigo return std::move(err);
57*4f676c25SWalter Erquinigo return lowest_tsc;
58*4f676c25SWalter Erquinigo }
59*4f676c25SWalter Erquinigo
Decode(Thread & thread)60a7d6c3efSWalter Erquinigo Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
616a5355e8SWalter Erquinigo if (Error err = CorrelateContextSwitchesAndIntelPtTraces())
62a7d6c3efSWalter Erquinigo return std::move(err);
63a7d6c3efSWalter Erquinigo
649f9464e0SPeicong Wu TraceIntelPTSP trace_sp = GetTrace();
659f9464e0SPeicong Wu
669f9464e0SPeicong Wu return trace_sp
679f9464e0SPeicong Wu ->GetThreadTimer(thread.GetID())
689f9464e0SPeicong Wu .TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> {
696a5355e8SWalter Erquinigo auto it = m_decoded_threads.find(thread.GetID());
706a5355e8SWalter Erquinigo if (it != m_decoded_threads.end())
716a5355e8SWalter Erquinigo return it->second;
726a5355e8SWalter Erquinigo
73*4f676c25SWalter Erquinigo DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(
74*4f676c25SWalter Erquinigo thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion());
756a5355e8SWalter Erquinigo
76ea37cd52SWalter Erquinigo Error err = trace_sp->OnAllCpusBinaryDataRead(
776a5355e8SWalter Erquinigo IntelPTDataKinds::kIptTrace,
786a5355e8SWalter Erquinigo [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
799f9464e0SPeicong Wu auto it =
809f9464e0SPeicong Wu m_continuous_executions_per_thread->find(thread.GetID());
816a5355e8SWalter Erquinigo if (it != m_continuous_executions_per_thread->end())
829f9464e0SPeicong Wu return DecodeSystemWideTraceForThread(
839f9464e0SPeicong Wu *decoded_thread_sp, *trace_sp, buffers, it->second);
846a5355e8SWalter Erquinigo
856a5355e8SWalter Erquinigo return Error::success();
866a5355e8SWalter Erquinigo });
876a5355e8SWalter Erquinigo if (err)
88a7d6c3efSWalter Erquinigo return std::move(err);
896a5355e8SWalter Erquinigo
906a5355e8SWalter Erquinigo m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp);
916a5355e8SWalter Erquinigo return decoded_thread_sp;
929f9464e0SPeicong Wu });
936a5355e8SWalter Erquinigo }
946a5355e8SWalter Erquinigo
956a5355e8SWalter Erquinigo static Expected<std::vector<IntelPTThreadSubtrace>>
GetIntelPTSubtracesForCpu(TraceIntelPT & trace,cpu_id_t cpu_id)966a5355e8SWalter Erquinigo GetIntelPTSubtracesForCpu(TraceIntelPT &trace, cpu_id_t cpu_id) {
976a5355e8SWalter Erquinigo std::vector<IntelPTThreadSubtrace> intel_pt_subtraces;
986a5355e8SWalter Erquinigo Error err = trace.OnCpuBinaryDataRead(
996a5355e8SWalter Erquinigo cpu_id, IntelPTDataKinds::kIptTrace,
1006a5355e8SWalter Erquinigo [&](ArrayRef<uint8_t> data) -> Error {
1016a5355e8SWalter Erquinigo Expected<std::vector<IntelPTThreadSubtrace>> split_trace =
1026a5355e8SWalter Erquinigo SplitTraceInContinuousExecutions(trace, data);
1036a5355e8SWalter Erquinigo if (!split_trace)
1046a5355e8SWalter Erquinigo return split_trace.takeError();
1056a5355e8SWalter Erquinigo
1066a5355e8SWalter Erquinigo intel_pt_subtraces = std::move(*split_trace);
1076a5355e8SWalter Erquinigo return Error::success();
1086a5355e8SWalter Erquinigo });
1096a5355e8SWalter Erquinigo if (err)
1106a5355e8SWalter Erquinigo return std::move(err);
1116a5355e8SWalter Erquinigo return intel_pt_subtraces;
1126a5355e8SWalter Erquinigo }
1136a5355e8SWalter Erquinigo
1146a5355e8SWalter Erquinigo Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
DoCorrelateContextSwitchesAndIntelPtTraces()1156a5355e8SWalter Erquinigo TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {
1166a5355e8SWalter Erquinigo DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>
1176a5355e8SWalter Erquinigo continuous_executions_per_thread;
118ea37cd52SWalter Erquinigo TraceIntelPTSP trace_sp = GetTrace();
1196a5355e8SWalter Erquinigo
1206a5355e8SWalter Erquinigo Optional<LinuxPerfZeroTscConversion> conv_opt =
121ea37cd52SWalter Erquinigo trace_sp->GetPerfZeroTscConversion();
1226a5355e8SWalter Erquinigo if (!conv_opt)
1236a5355e8SWalter Erquinigo return createStringError(
1246a5355e8SWalter Erquinigo inconvertibleErrorCode(),
1256a5355e8SWalter Erquinigo "TSC to nanoseconds conversion values were not found");
1266a5355e8SWalter Erquinigo
1276a5355e8SWalter Erquinigo LinuxPerfZeroTscConversion tsc_conversion = *conv_opt;
1286a5355e8SWalter Erquinigo
129ea37cd52SWalter Erquinigo for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) {
1306a5355e8SWalter Erquinigo Expected<std::vector<IntelPTThreadSubtrace>> intel_pt_subtraces =
131ea37cd52SWalter Erquinigo GetIntelPTSubtracesForCpu(*trace_sp, cpu_id);
1326a5355e8SWalter Erquinigo if (!intel_pt_subtraces)
1336a5355e8SWalter Erquinigo return intel_pt_subtraces.takeError();
1346a5355e8SWalter Erquinigo
135d30fd5c3SGaurav Gaur m_total_psb_blocks += intel_pt_subtraces->size();
1366a5355e8SWalter Erquinigo // We'll be iterating through the thread continuous executions and the intel
1376a5355e8SWalter Erquinigo // pt subtraces sorted by time.
1386a5355e8SWalter Erquinigo auto it = intel_pt_subtraces->begin();
1396a5355e8SWalter Erquinigo auto on_new_thread_execution =
1406a5355e8SWalter Erquinigo [&](const ThreadContinuousExecution &thread_execution) {
1416a5355e8SWalter Erquinigo IntelPTThreadContinousExecution execution(thread_execution);
1426a5355e8SWalter Erquinigo
1436a5355e8SWalter Erquinigo for (; it != intel_pt_subtraces->end() &&
1446a5355e8SWalter Erquinigo it->tsc < thread_execution.GetEndTSC();
1456a5355e8SWalter Erquinigo it++) {
1466a5355e8SWalter Erquinigo if (it->tsc > thread_execution.GetStartTSC()) {
1476a5355e8SWalter Erquinigo execution.intelpt_subtraces.push_back(*it);
1486a5355e8SWalter Erquinigo } else {
149d30fd5c3SGaurav Gaur m_unattributed_psb_blocks++;
1506a5355e8SWalter Erquinigo }
1516a5355e8SWalter Erquinigo }
1526a5355e8SWalter Erquinigo continuous_executions_per_thread[thread_execution.tid].push_back(
1536a5355e8SWalter Erquinigo execution);
1546a5355e8SWalter Erquinigo };
155ea37cd52SWalter Erquinigo Error err = trace_sp->OnCpuBinaryDataRead(
1566a5355e8SWalter Erquinigo cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,
1576a5355e8SWalter Erquinigo [&](ArrayRef<uint8_t> data) -> Error {
1586a5355e8SWalter Erquinigo Expected<std::vector<ThreadContinuousExecution>> executions =
1596a5355e8SWalter Erquinigo DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion);
1606a5355e8SWalter Erquinigo if (!executions)
1616a5355e8SWalter Erquinigo return executions.takeError();
1626a5355e8SWalter Erquinigo for (const ThreadContinuousExecution &exec : *executions)
1636a5355e8SWalter Erquinigo on_new_thread_execution(exec);
1646a5355e8SWalter Erquinigo return Error::success();
1656a5355e8SWalter Erquinigo });
1666a5355e8SWalter Erquinigo if (err)
1676a5355e8SWalter Erquinigo return std::move(err);
168d30fd5c3SGaurav Gaur
169d30fd5c3SGaurav Gaur m_unattributed_psb_blocks += intel_pt_subtraces->end() - it;
1706a5355e8SWalter Erquinigo }
1716a5355e8SWalter Erquinigo // We now sort the executions of each thread to have them ready for
1726a5355e8SWalter Erquinigo // instruction decoding
1736a5355e8SWalter Erquinigo for (auto &tid_executions : continuous_executions_per_thread)
1746a5355e8SWalter Erquinigo std::sort(tid_executions.second.begin(), tid_executions.second.end());
1756a5355e8SWalter Erquinigo
1766a5355e8SWalter Erquinigo return continuous_executions_per_thread;
1776a5355e8SWalter Erquinigo }
1786a5355e8SWalter Erquinigo
CorrelateContextSwitchesAndIntelPtTraces()1796a5355e8SWalter Erquinigo Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
1806a5355e8SWalter Erquinigo if (m_setup_error)
1816a5355e8SWalter Erquinigo return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
1826a5355e8SWalter Erquinigo
1836a5355e8SWalter Erquinigo if (m_continuous_executions_per_thread)
1846a5355e8SWalter Erquinigo return Error::success();
1856a5355e8SWalter Erquinigo
1869f9464e0SPeicong Wu Error err = GetTrace()->GetGlobalTimer().TimeTask(
1876a5355e8SWalter Erquinigo "Context switch and Intel PT traces correlation", [&]() -> Error {
1886a5355e8SWalter Erquinigo if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) {
1896a5355e8SWalter Erquinigo m_continuous_executions_per_thread.emplace(std::move(*correlation));
1906a5355e8SWalter Erquinigo return Error::success();
1916a5355e8SWalter Erquinigo } else {
1926a5355e8SWalter Erquinigo return correlation.takeError();
1936a5355e8SWalter Erquinigo }
1946a5355e8SWalter Erquinigo });
1956a5355e8SWalter Erquinigo if (err) {
1966a5355e8SWalter Erquinigo m_setup_error = toString(std::move(err));
1976a5355e8SWalter Erquinigo return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
1986a5355e8SWalter Erquinigo }
1996a5355e8SWalter Erquinigo return Error::success();
2006a5355e8SWalter Erquinigo }
2016a5355e8SWalter Erquinigo
GetNumContinuousExecutionsForThread(lldb::tid_t tid) const2026a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread(
2036a5355e8SWalter Erquinigo lldb::tid_t tid) const {
2046a5355e8SWalter Erquinigo if (!m_continuous_executions_per_thread)
2056a5355e8SWalter Erquinigo return 0;
2066a5355e8SWalter Erquinigo auto it = m_continuous_executions_per_thread->find(tid);
2076a5355e8SWalter Erquinigo if (it == m_continuous_executions_per_thread->end())
2086a5355e8SWalter Erquinigo return 0;
2096a5355e8SWalter Erquinigo return it->second.size();
2106a5355e8SWalter Erquinigo }
2116a5355e8SWalter Erquinigo
GetTotalContinuousExecutionsCount() const2126a5355e8SWalter Erquinigo size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const {
2136a5355e8SWalter Erquinigo if (!m_continuous_executions_per_thread)
2146a5355e8SWalter Erquinigo return 0;
2156a5355e8SWalter Erquinigo size_t count = 0;
2166a5355e8SWalter Erquinigo for (const auto &kv : *m_continuous_executions_per_thread)
2176a5355e8SWalter Erquinigo count += kv.second.size();
2186a5355e8SWalter Erquinigo return count;
2196a5355e8SWalter Erquinigo }
220d30fd5c3SGaurav Gaur
221d30fd5c3SGaurav Gaur size_t
GePSBBlocksCountForThread(lldb::tid_t tid) const222d30fd5c3SGaurav Gaur TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const {
223d30fd5c3SGaurav Gaur if (!m_continuous_executions_per_thread)
224d30fd5c3SGaurav Gaur return 0;
225d30fd5c3SGaurav Gaur size_t count = 0;
226d30fd5c3SGaurav Gaur auto it = m_continuous_executions_per_thread->find(tid);
2270466d1dfSymeng if (it == m_continuous_executions_per_thread->end())
2280466d1dfSymeng return 0;
229d30fd5c3SGaurav Gaur for (const IntelPTThreadContinousExecution &execution : it->second)
230d30fd5c3SGaurav Gaur count += execution.intelpt_subtraces.size();
231d30fd5c3SGaurav Gaur return count;
232d30fd5c3SGaurav Gaur }
233d30fd5c3SGaurav Gaur
GetUnattributedPSBBlocksCount() const234d30fd5c3SGaurav Gaur size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const {
235d30fd5c3SGaurav Gaur return m_unattributed_psb_blocks;
236d30fd5c3SGaurav Gaur }
237d30fd5c3SGaurav Gaur
GetTotalPSBBlocksCount() const238d30fd5c3SGaurav Gaur size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const {
239d30fd5c3SGaurav Gaur return m_total_psb_blocks;
240d30fd5c3SGaurav Gaur }
241