brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.4 KiB · 06551a4 Raw
265 lines · cpp
1//===-- IntelPTCollector.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 "IntelPTCollector.h"10#include "Perf.h"11#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"12#include "Procfs.h"13#include "lldb/Utility/StreamString.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/Support/Error.h"16#include "llvm/Support/MathExtras.h"17#include <algorithm>18#include <cstddef>19#include <fcntl.h>20#include <fstream>21#include <linux/perf_event.h>22#include <optional>23#include <sstream>24#include <sys/ioctl.h>25#include <sys/syscall.h>26 27using namespace lldb;28using namespace lldb_private;29using namespace process_linux;30using namespace llvm;31 32IntelPTCollector::IntelPTCollector(NativeProcessProtocol &process)33    : m_process(process) {}34 35llvm::Expected<LinuxPerfZeroTscConversion &>36IntelPTCollector::FetchPerfTscConversionParameters() {37  if (Expected<LinuxPerfZeroTscConversion> tsc_conversion =38          LoadPerfTscConversionParameters())39    return *tsc_conversion;40  else41    return createStringError(inconvertibleErrorCode(),42                             "Unable to load TSC to wall time conversion: %s",43                             toString(tsc_conversion.takeError()).c_str());44}45 46Error IntelPTCollector::TraceStop(lldb::tid_t tid) {47  if (m_process_trace_up && m_process_trace_up->TracesThread(tid))48    return m_process_trace_up->TraceStop(tid);49  return m_thread_traces.TraceStop(tid);50}51 52Error IntelPTCollector::TraceStop(const TraceStopRequest &request) {53  if (request.IsProcessTracing()) {54    Clear();55    return Error::success();56  } else {57    Error error = Error::success();58    for (int64_t tid : *request.tids)59      error = joinErrors(std::move(error),60                         TraceStop(static_cast<lldb::tid_t>(tid)));61    return error;62  }63}64 65/// \return66///   some file descriptor in /sys/fs/ associated with the cgroup of the given67///   pid, or \a std::nullopt if the pid is not part of a cgroup.68static std::optional<int> GetCGroupFileDescriptor(lldb::pid_t pid) {69  static std::optional<int> fd;70  if (fd)71    return fd;72 73  std::ifstream ifile;74  ifile.open(formatv("/proc/{0}/cgroup", pid));75  if (!ifile)76    return std::nullopt;77 78  std::string line;79  while (std::getline(ifile, line)) {80    if (line.find("0:") != 0)81      continue;82 83    std::string slice = line.substr(line.find_first_of('/'));84    if (slice.empty())85      return std::nullopt;86    std::string cgroup_file = formatv("/sys/fs/cgroup/{0}", slice);87    // This cgroup should for the duration of the target, so we don't need to88    // invoke close ourselves.89    int maybe_fd = open(cgroup_file.c_str(), O_RDONLY);90    if (maybe_fd != -1) {91      fd = maybe_fd;92      return fd;93    }94  }95  return std::nullopt;96}97 98Error IntelPTCollector::TraceStart(const TraceIntelPTStartRequest &request) {99  if (request.IsProcessTracing()) {100    if (m_process_trace_up) {101      return createStringError(102          inconvertibleErrorCode(),103          "Process currently traced. Stop process tracing first");104    }105    if (request.IsPerCpuTracing()) {106      if (m_thread_traces.GetTracedThreadsCount() > 0)107        return createStringError(108            inconvertibleErrorCode(),109            "Threads currently traced. Stop tracing them first.");110      // CPU tracing is useless if we can't convert tsc to nanos.111      Expected<LinuxPerfZeroTscConversion &> tsc_conversion =112          FetchPerfTscConversionParameters();113      if (!tsc_conversion)114        return tsc_conversion.takeError();115 116      // We force the enablement of TSCs, which is needed for correlating the117      // cpu traces.118      TraceIntelPTStartRequest effective_request = request;119      effective_request.enable_tsc = true;120 121      // We try to use cgroup filtering whenever possible122      std::optional<int> cgroup_fd;123      if (!request.disable_cgroup_filtering.value_or(false))124        cgroup_fd = GetCGroupFileDescriptor(m_process.GetID());125 126      if (Expected<IntelPTProcessTraceUP> trace =127              IntelPTMultiCoreTrace::StartOnAllCores(effective_request,128                                                     m_process, cgroup_fd)) {129        m_process_trace_up = std::move(*trace);130        return Error::success();131      } else {132        return trace.takeError();133      }134    } else {135      std::vector<lldb::tid_t> process_threads;136      for (NativeThreadProtocol &thread : m_process.Threads())137        process_threads.push_back(thread.GetID());138 139      // per-thread process tracing140      if (Expected<IntelPTProcessTraceUP> trace =141              IntelPTPerThreadProcessTrace::Start(request, process_threads)) {142        m_process_trace_up = std::move(trace.get());143        return Error::success();144      } else {145        return trace.takeError();146      }147    }148  } else {149    // individual thread tracing150    Error error = Error::success();151    for (int64_t tid : *request.tids) {152      if (m_process_trace_up && m_process_trace_up->TracesThread(tid))153        error = joinErrors(154            std::move(error),155            createStringError(inconvertibleErrorCode(),156                              formatv("Thread with tid {0} is currently "157                                      "traced. Stop tracing it first.",158                                      tid)159                                  .str()160                                  .c_str()));161      else162        error = joinErrors(std::move(error),163                           m_thread_traces.TraceStart(tid, request));164    }165    return error;166  }167}168 169void IntelPTCollector::ProcessWillResume() {170  if (m_process_trace_up)171    m_process_trace_up->ProcessWillResume();172}173 174void IntelPTCollector::ProcessDidStop() {175  if (m_process_trace_up)176    m_process_trace_up->ProcessDidStop();177}178 179Error IntelPTCollector::OnThreadCreated(lldb::tid_t tid) {180  if (m_process_trace_up)181    return m_process_trace_up->TraceStart(tid);182 183  return Error::success();184}185 186Error IntelPTCollector::OnThreadDestroyed(lldb::tid_t tid) {187  if (m_process_trace_up && m_process_trace_up->TracesThread(tid))188    return m_process_trace_up->TraceStop(tid);189  else if (m_thread_traces.TracesThread(tid))190    return m_thread_traces.TraceStop(tid);191  return Error::success();192}193 194Expected<json::Value> IntelPTCollector::GetState() {195  Expected<ArrayRef<uint8_t>> cpu_info = GetProcfsCpuInfo();196  if (!cpu_info)197    return cpu_info.takeError();198 199  TraceIntelPTGetStateResponse state;200  if (m_process_trace_up)201    state = m_process_trace_up->GetState();202 203  state.process_binary_data.push_back(204      {IntelPTDataKinds::kProcFsCpuInfo, cpu_info->size()});205 206  m_thread_traces.ForEachThread(207      [&](lldb::tid_t tid, const IntelPTSingleBufferTrace &thread_trace) {208        state.traced_threads.push_back(209            {tid,210             {{IntelPTDataKinds::kIptTrace, thread_trace.GetIptTraceSize()}}});211      });212 213  if (Expected<LinuxPerfZeroTscConversion &> tsc_conversion =214          FetchPerfTscConversionParameters())215    state.tsc_perf_zero_conversion = *tsc_conversion;216  else217    state.AddWarning(toString(tsc_conversion.takeError()));218  return toJSON(state);219}220 221Expected<std::vector<uint8_t>>222IntelPTCollector::GetBinaryData(const TraceGetBinaryDataRequest &request) {223  if (request.kind == IntelPTDataKinds::kProcFsCpuInfo)224    return GetProcfsCpuInfo();225 226  if (m_process_trace_up) {227    Expected<std::optional<std::vector<uint8_t>>> data =228        m_process_trace_up->TryGetBinaryData(request);229    if (!data)230      return data.takeError();231    if (*data)232      return **data;233  }234 235  {236    Expected<std::optional<std::vector<uint8_t>>> data =237        m_thread_traces.TryGetBinaryData(request);238    if (!data)239      return data.takeError();240    if (*data)241      return **data;242  }243 244  return createStringError(245      inconvertibleErrorCode(),246      formatv("Can't fetch data kind {0} for cpu_id {1}, tid {2} and "247              "\"process tracing\" mode {3}",248              request.kind, request.cpu_id, request.tid,249              m_process_trace_up ? "enabled" : "not enabled"));250}251 252bool IntelPTCollector::IsSupported() {253  if (Expected<uint32_t> intel_pt_type = GetIntelPTOSEventType()) {254    return true;255  } else {256    llvm::consumeError(intel_pt_type.takeError());257    return false;258  }259}260 261void IntelPTCollector::Clear() {262  m_process_trace_up.reset();263  m_thread_traces.Clear();264}265