brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.1 KiB · 376bd5c Raw
166 lines · cpp
1//===-- IntelPTMultiCoreTrace.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 "IntelPTMultiCoreTrace.h"10#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"11#include "Procfs.h"12#include <optional>13 14using namespace lldb;15using namespace lldb_private;16using namespace process_linux;17using namespace llvm;18 19static bool IsTotalBufferLimitReached(ArrayRef<cpu_id_t> cores,20                                      const TraceIntelPTStartRequest &request) {21  uint64_t required = cores.size() * request.ipt_trace_size;22  uint64_t limit = request.process_buffer_size_limit.value_or(23      std::numeric_limits<uint64_t>::max());24  return required > limit;25}26 27static Error IncludePerfEventParanoidMessageInError(Error &&error) {28  return createStringError(29      inconvertibleErrorCode(),30      "%s\nYou might need to rerun as sudo or to set "31      "/proc/sys/kernel/perf_event_paranoid to a value of 0 or -1. You can use "32      "`sudo sysctl -w kernel.perf_event_paranoid=-1` for that.",33      toString(std::move(error)).c_str());34}35 36Expected<std::unique_ptr<IntelPTMultiCoreTrace>>37IntelPTMultiCoreTrace::StartOnAllCores(const TraceIntelPTStartRequest &request,38                                       NativeProcessProtocol &process,39                                       std::optional<int> cgroup_fd) {40  Expected<ArrayRef<cpu_id_t>> cpu_ids = GetAvailableLogicalCoreIDs();41  if (!cpu_ids)42    return cpu_ids.takeError();43 44  if (IsTotalBufferLimitReached(*cpu_ids, request))45    return createStringError(46        inconvertibleErrorCode(),47        "The process can't be traced because the process trace size limit "48        "has been reached. Consider retracing with a higher limit.");49 50  DenseMap<cpu_id_t, std::pair<IntelPTSingleBufferTrace, ContextSwitchTrace>>51      traces;52 53  for (cpu_id_t cpu_id : *cpu_ids) {54    Expected<IntelPTSingleBufferTrace> core_trace =55        IntelPTSingleBufferTrace::Start(request, /*tid=*/std::nullopt, cpu_id,56                                        /*disabled=*/true, cgroup_fd);57    if (!core_trace)58      return IncludePerfEventParanoidMessageInError(core_trace.takeError());59 60    if (Expected<PerfEvent> context_switch_trace =61            CreateContextSwitchTracePerfEvent(cpu_id,62                                              &core_trace->GetPerfEvent())) {63      traces.try_emplace(cpu_id,64                         std::make_pair(std::move(*core_trace),65                                        std::move(*context_switch_trace)));66    } else {67      return context_switch_trace.takeError();68    }69  }70 71  return std::unique_ptr<IntelPTMultiCoreTrace>(72      new IntelPTMultiCoreTrace(std::move(traces), process, (bool)cgroup_fd));73}74 75void IntelPTMultiCoreTrace::ForEachCore(76    std::function<void(cpu_id_t cpu_id, IntelPTSingleBufferTrace &core_trace)>77        callback) {78  for (auto &it : m_traces_per_core)79    callback(it.first, it.second.first);80}81 82void IntelPTMultiCoreTrace::ForEachCore(83    std::function<void(cpu_id_t cpu_id, IntelPTSingleBufferTrace &intelpt_trace,84                       ContextSwitchTrace &context_switch_trace)>85        callback) {86  for (auto &it : m_traces_per_core)87    callback(it.first, it.second.first, it.second.second);88}89 90void IntelPTMultiCoreTrace::ProcessDidStop() {91  ForEachCore([](cpu_id_t cpu_id, IntelPTSingleBufferTrace &core_trace) {92    if (Error err = core_trace.Pause()) {93      LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), std::move(err),94                     "Unable to pause the core trace for core {0}", cpu_id);95    }96  });97}98 99void IntelPTMultiCoreTrace::ProcessWillResume() {100  ForEachCore([](cpu_id_t cpu_id, IntelPTSingleBufferTrace &core_trace) {101    if (Error err = core_trace.Resume()) {102      LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), std::move(err),103                     "Unable to resume the core trace for core {0}", cpu_id);104    }105  });106}107 108TraceIntelPTGetStateResponse IntelPTMultiCoreTrace::GetState() {109  TraceIntelPTGetStateResponse state;110  state.using_cgroup_filtering = m_using_cgroup_filtering;111 112  for (NativeThreadProtocol &thread : m_process.Threads())113    state.traced_threads.push_back(TraceThreadState{thread.GetID(), {}});114 115  state.cpus.emplace();116  ForEachCore([&](lldb::cpu_id_t cpu_id,117                  const IntelPTSingleBufferTrace &core_trace,118                  const ContextSwitchTrace &context_switch_trace) {119    state.cpus->push_back(120        {cpu_id,121         {{IntelPTDataKinds::kIptTrace, core_trace.GetIptTraceSize()},122          {IntelPTDataKinds::kPerfContextSwitchTrace,123           context_switch_trace.GetEffectiveDataBufferSize()}}});124  });125 126  return state;127}128 129bool IntelPTMultiCoreTrace::TracesThread(lldb::tid_t tid) const {130  // All the process' threads are being traced automatically.131  return (bool)m_process.GetThreadByID(tid);132}133 134llvm::Error IntelPTMultiCoreTrace::TraceStart(lldb::tid_t tid) {135  // All the process' threads are being traced automatically.136  if (!TracesThread(tid))137    return createStringError(138        inconvertibleErrorCode(),139        "Thread %" PRIu64 " is not part of the target process", tid);140  return Error::success();141}142 143Error IntelPTMultiCoreTrace::TraceStop(lldb::tid_t tid) {144  return createStringError(inconvertibleErrorCode(),145                           "Can't stop tracing an individual thread when "146                           "per-cpu process tracing is enabled.");147}148 149Expected<std::optional<std::vector<uint8_t>>>150IntelPTMultiCoreTrace::TryGetBinaryData(151    const TraceGetBinaryDataRequest &request) {152  if (!request.cpu_id)153    return std::nullopt;154  auto it = m_traces_per_core.find(*request.cpu_id);155  if (it == m_traces_per_core.end())156    return createStringError(157        inconvertibleErrorCode(),158        formatv("Core {0} is not being traced", *request.cpu_id));159 160  if (request.kind == IntelPTDataKinds::kIptTrace)161    return it->second.first.GetIptTrace();162  if (request.kind == IntelPTDataKinds::kPerfContextSwitchTrace)163    return it->second.second.GetReadOnlyDataBuffer();164  return std::nullopt;165}166