brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · e2ca8b4 Raw
239 lines · cpp
1//===-- TraceIntelPTMultiCpuDecoder.cpp -----------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "TraceIntelPTMultiCpuDecoder.h"10#include "TraceIntelPT.h"11#include "llvm/Support/Error.h"12#include <optional>13 14using namespace lldb;15using namespace lldb_private;16using namespace lldb_private::trace_intel_pt;17using namespace llvm;18 19TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder(20    TraceIntelPTSP trace_sp)21    : m_trace_wp(trace_sp) {22  for (Process *proc : trace_sp->GetAllProcesses()) {23    for (ThreadSP thread_sp : proc->GetThreadList().Threads()) {24      m_tids.insert(thread_sp->GetID());25    }26  }27}28 29TraceIntelPTSP TraceIntelPTMultiCpuDecoder::GetTrace() {30  return m_trace_wp.lock();31}32 33bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const {34  return m_tids.count(tid);35}36 37Expected<std::optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() {38  std::optional<uint64_t> lowest_tsc;39  TraceIntelPTSP trace_sp = GetTrace();40 41  Error err = GetTrace()->OnAllCpusBinaryDataRead(42      IntelPTDataKinds::kIptTrace,43      [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {44        for (auto &cpu_id_to_buffer : buffers) {45          Expected<std::optional<uint64_t>> tsc =46              FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second);47          if (!tsc)48            return tsc.takeError();49          if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))50            lowest_tsc = **tsc;51        }52        return Error::success();53      });54  if (err)55    return std::move(err);56  return lowest_tsc;57}58 59Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {60  if (Error err = CorrelateContextSwitchesAndIntelPtTraces())61    return std::move(err);62 63  TraceIntelPTSP trace_sp = GetTrace();64 65  return trace_sp->GetThreadTimer(thread.GetID())66      .TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> {67        auto it = m_decoded_threads.find(thread.GetID());68        if (it != m_decoded_threads.end())69          return it->second;70 71        DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(72            thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion());73 74        Error err = trace_sp->OnAllCpusBinaryDataRead(75            IntelPTDataKinds::kIptTrace,76            [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {77              auto it =78                  m_continuous_executions_per_thread->find(thread.GetID());79              if (it != m_continuous_executions_per_thread->end())80                return DecodeSystemWideTraceForThread(81                    *decoded_thread_sp, *trace_sp, buffers, it->second);82 83              return Error::success();84            });85        if (err)86          return std::move(err);87 88        m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp);89        return decoded_thread_sp;90      });91}92 93static Expected<std::vector<PSBBlock>> GetPSBBlocksForCPU(TraceIntelPT &trace,94                                                          cpu_id_t cpu_id) {95  std::vector<PSBBlock> psb_blocks;96  Error err = trace.OnCpuBinaryDataRead(97      cpu_id, IntelPTDataKinds::kIptTrace,98      [&](ArrayRef<uint8_t> data) -> Error {99        Expected<std::vector<PSBBlock>> split_trace =100            SplitTraceIntoPSBBlock(trace, data, /*expect_tscs=*/true);101        if (!split_trace)102          return split_trace.takeError();103 104        psb_blocks = std::move(*split_trace);105        return Error::success();106      });107  if (err)108    return std::move(err);109  return psb_blocks;110}111 112Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>113TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {114  DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>115      continuous_executions_per_thread;116  TraceIntelPTSP trace_sp = GetTrace();117 118  std::optional<LinuxPerfZeroTscConversion> conv_opt =119      trace_sp->GetPerfZeroTscConversion();120  if (!conv_opt)121    return createStringError(122        inconvertibleErrorCode(),123        "TSC to nanoseconds conversion values were not found");124 125  LinuxPerfZeroTscConversion tsc_conversion = *conv_opt;126 127  for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) {128    Expected<std::vector<PSBBlock>> psb_blocks =129        GetPSBBlocksForCPU(*trace_sp, cpu_id);130    if (!psb_blocks)131      return psb_blocks.takeError();132 133    m_total_psb_blocks += psb_blocks->size();134    // We'll be iterating through the thread continuous executions and the intel135    // pt subtraces sorted by time.136    auto it = psb_blocks->begin();137    auto on_new_thread_execution =138        [&](const ThreadContinuousExecution &thread_execution) {139          IntelPTThreadContinousExecution execution(thread_execution);140 141          for (; it != psb_blocks->end() &&142                 *it->tsc < thread_execution.GetEndTSC();143               it++) {144            if (*it->tsc > thread_execution.GetStartTSC()) {145              execution.psb_blocks.push_back(*it);146            } else {147              m_unattributed_psb_blocks++;148            }149          }150          continuous_executions_per_thread[thread_execution.tid].push_back(151              execution);152        };153    Error err = trace_sp->OnCpuBinaryDataRead(154        cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,155        [&](ArrayRef<uint8_t> data) -> Error {156          Expected<std::vector<ThreadContinuousExecution>> executions =157              DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion);158          if (!executions)159            return executions.takeError();160          for (const ThreadContinuousExecution &exec : *executions)161            on_new_thread_execution(exec);162          return Error::success();163        });164    if (err)165      return std::move(err);166 167    m_unattributed_psb_blocks += psb_blocks->end() - it;168  }169  // We now sort the executions of each thread to have them ready for170  // instruction decoding171  for (auto &tid_executions : continuous_executions_per_thread)172    std::sort(tid_executions.second.begin(), tid_executions.second.end());173 174  return continuous_executions_per_thread;175}176 177Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() {178  if (m_setup_error)179    return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());180 181  if (m_continuous_executions_per_thread)182    return Error::success();183 184  Error err = GetTrace()->GetGlobalTimer().TimeTask(185      "Context switch and Intel PT traces correlation", [&]() -> Error {186        if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) {187          m_continuous_executions_per_thread.emplace(std::move(*correlation));188          return Error::success();189        } else {190          return correlation.takeError();191        }192      });193  if (err) {194    m_setup_error = toString(std::move(err));195    return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());196  }197  return Error::success();198}199 200size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread(201    lldb::tid_t tid) const {202  if (!m_continuous_executions_per_thread)203    return 0;204  auto it = m_continuous_executions_per_thread->find(tid);205  if (it == m_continuous_executions_per_thread->end())206    return 0;207  return it->second.size();208}209 210size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const {211  if (!m_continuous_executions_per_thread)212    return 0;213  size_t count = 0;214  for (const auto &kv : *m_continuous_executions_per_thread)215    count += kv.second.size();216  return count;217}218 219size_t220TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const {221  if (!m_continuous_executions_per_thread)222    return 0;223  size_t count = 0;224  auto it = m_continuous_executions_per_thread->find(tid);225  if (it == m_continuous_executions_per_thread->end())226    return 0;227  for (const IntelPTThreadContinousExecution &execution : it->second)228    count += execution.psb_blocks.size();229  return count;230}231 232size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const {233  return m_unattributed_psb_blocks;234}235 236size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const {237  return m_total_psb_blocks;238}239