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