LLDB  mainline
IntelPTMultiCoreTrace.cpp
Go to the documentation of this file.
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
11 #include "Procfs.h"
12 
13 using namespace lldb;
14 using namespace lldb_private;
15 using namespace process_linux;
16 using namespace llvm;
17 
18 static bool IsTotalBufferLimitReached(ArrayRef<cpu_id_t> cores,
19  const TraceIntelPTStartRequest &request) {
20  uint64_t required = cores.size() * request.ipt_trace_size;
21  uint64_t limit = request.process_buffer_size_limit.value_or(
22  std::numeric_limits<uint64_t>::max());
23  return required > limit;
24 }
25 
27  return createStringError(
28  inconvertibleErrorCode(),
29  "%s\nYou might need to rerun as sudo or to set "
30  "/proc/sys/kernel/perf_event_paranoid to a value of 0 or -1. You can use "
31  "`sudo sysctl -w kernel.perf_event_paranoid=-1` for that.",
32  toString(std::move(error)).c_str());
33 }
34 
35 Expected<std::unique_ptr<IntelPTMultiCoreTrace>>
36 IntelPTMultiCoreTrace::StartOnAllCores(const TraceIntelPTStartRequest &request,
37  NativeProcessProtocol &process,
38  Optional<int> cgroup_fd) {
39  Expected<ArrayRef<cpu_id_t>> cpu_ids = GetAvailableLogicalCoreIDs();
40  if (!cpu_ids)
41  return cpu_ids.takeError();
42 
43  if (IsTotalBufferLimitReached(*cpu_ids, request))
44  return createStringError(
45  inconvertibleErrorCode(),
46  "The process can't be traced because the process trace size limit "
47  "has been reached. Consider retracing with a higher limit.");
48 
49  DenseMap<cpu_id_t, std::pair<IntelPTSingleBufferTrace, ContextSwitchTrace>>
50  traces;
51 
52  for (cpu_id_t cpu_id : *cpu_ids) {
53  Expected<IntelPTSingleBufferTrace> core_trace =
54  IntelPTSingleBufferTrace::Start(request, /*tid=*/None, cpu_id,
55  /*disabled=*/true, cgroup_fd);
56  if (!core_trace)
57  return IncludePerfEventParanoidMessageInError(core_trace.takeError());
58 
59  if (Expected<PerfEvent> context_switch_trace =
61  &core_trace->GetPerfEvent())) {
62  traces.try_emplace(cpu_id,
63  std::make_pair(std::move(*core_trace),
64  std::move(*context_switch_trace)));
65  } else {
66  return context_switch_trace.takeError();
67  }
68  }
69 
70  return std::unique_ptr<IntelPTMultiCoreTrace>(
71  new IntelPTMultiCoreTrace(std::move(traces), process, (bool)cgroup_fd));
72 }
73 
74 void IntelPTMultiCoreTrace::ForEachCore(
75  std::function<void(cpu_id_t cpu_id, IntelPTSingleBufferTrace &core_trace)>
76  callback) {
77  for (auto &it : m_traces_per_core)
78  callback(it.first, it.second.first);
79 }
80 
81 void IntelPTMultiCoreTrace::ForEachCore(
82  std::function<void(cpu_id_t cpu_id, IntelPTSingleBufferTrace &intelpt_trace,
83  ContextSwitchTrace &context_switch_trace)>
84  callback) {
85  for (auto &it : m_traces_per_core)
86  callback(it.first, it.second.first, it.second.second);
87 }
88 
89 void IntelPTMultiCoreTrace::ProcessDidStop() {
90  ForEachCore([](cpu_id_t cpu_id, IntelPTSingleBufferTrace &core_trace) {
91  if (Error err = core_trace.Pause()) {
92  LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), std::move(err),
93  "Unable to pause the core trace for core {0}", cpu_id);
94  }
95  });
96 }
97 
98 void IntelPTMultiCoreTrace::ProcessWillResume() {
99  ForEachCore([](cpu_id_t cpu_id, IntelPTSingleBufferTrace &core_trace) {
100  if (Error err = core_trace.Resume()) {
101  LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), std::move(err),
102  "Unable to resume the core trace for core {0}", cpu_id);
103  }
104  });
105 }
106 
107 TraceIntelPTGetStateResponse IntelPTMultiCoreTrace::GetState() {
109  state.using_cgroup_filtering = m_using_cgroup_filtering;
110 
111  for (NativeThreadProtocol &thread : m_process.Threads())
112  state.traced_threads.push_back(TraceThreadState{thread.GetID(), {}});
113 
114  state.cpus.emplace();
115  ForEachCore([&](lldb::cpu_id_t cpu_id,
116  const IntelPTSingleBufferTrace &core_trace,
117  const ContextSwitchTrace &context_switch_trace) {
118  state.cpus->push_back(
119  {cpu_id,
120  {{IntelPTDataKinds::kIptTrace, core_trace.GetIptTraceSize()},
121  {IntelPTDataKinds::kPerfContextSwitchTrace,
122  context_switch_trace.GetEffectiveDataBufferSize()}}});
123  });
124 
125  return state;
126 }
127 
128 bool IntelPTMultiCoreTrace::TracesThread(lldb::tid_t tid) const {
129  // All the process' threads are being traced automatically.
130  return (bool)m_process.GetThreadByID(tid);
131 }
132 
133 llvm::Error IntelPTMultiCoreTrace::TraceStart(lldb::tid_t tid) {
134  // All the process' threads are being traced automatically.
135  if (!TracesThread(tid))
136  return createStringError(
137  inconvertibleErrorCode(),
138  "Thread %" PRIu64 " is not part of the target process", tid);
139  return Error::success();
140 }
141 
142 Error IntelPTMultiCoreTrace::TraceStop(lldb::tid_t tid) {
143  return createStringError(inconvertibleErrorCode(),
144  "Can't stop tracing an individual thread when "
145  "per-cpu process tracing is enabled.");
146 }
147 
148 Expected<Optional<std::vector<uint8_t>>>
149 IntelPTMultiCoreTrace::TryGetBinaryData(
150  const TraceGetBinaryDataRequest &request) {
151  if (!request.cpu_id)
152  return None;
153  auto it = m_traces_per_core.find(*request.cpu_id);
154  if (it == m_traces_per_core.end())
155  return createStringError(
156  inconvertibleErrorCode(),
157  formatv("Core {0} is not being traced", *request.cpu_id));
158 
159  if (request.kind == IntelPTDataKinds::kIptTrace)
160  return it->second.first.GetIptTrace();
161  if (request.kind == IntelPTDataKinds::kPerfContextSwitchTrace)
162  return it->second.second.GetReadOnlyDataBuffer();
163  return None;
164 }
lldb_private::toString
const char * toString(AppleArm64ExceptionClass EC)
Definition: AppleArm64ExceptionClass.h:38
lldb_private::TraceGetStateResponse::traced_threads
std::vector< TraceThreadState > traced_threads
Definition: TraceGDBRemotePackets.h:133
lldb_private::TraceGetBinaryDataRequest::kind
std::string kind
Identifier for the data.
Definition: TraceGDBRemotePackets.h:153
llvm
Definition: Debugger.h:50
lldb_private::TraceGetBinaryDataRequest
jLLDBTraceGetBinaryData gdb-remote packet
Definition: TraceGDBRemotePackets.h:149
lldb_private::NativeThreadProtocol
Definition: NativeThreadProtocol.h:24
lldb_private::process_linux::PerfEvent::GetEffectiveDataBufferSize
size_t GetEffectiveDataBufferSize() const
Definition: Perf.cpp:297
lldb_private::TraceIntelPTGetStateResponse
Definition: TraceIntelPTGDBRemotePackets.h:111
IntelPTMultiCoreTrace.h
lldb_private::TraceIntelPTGetStateResponse::using_cgroup_filtering
bool using_cgroup_filtering
Definition: TraceIntelPTGDBRemotePackets.h:114
Procfs.h
lldb_private::TraceGetStateResponse::cpus
llvm::Optional< std::vector< TraceCpuState > > cpus
Definition: TraceGDBRemotePackets.h:135
lldb_private::process_linux::PerfEvent
Thin wrapper of the perf_event_open API.
Definition: Perf.h:80
lldb_private::process_linux::IntelPTSingleBufferTrace::Resume
llvm::Error Resume()
Resume the collection of this trace.
Definition: IntelPTSingleBufferTrace.cpp:208
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb_private::process_linux::GetAvailableLogicalCoreIDs
llvm::Expected< std::vector< lldb::cpu_id_t > > GetAvailableLogicalCoreIDs(llvm::StringRef cpuinfo)
lldb_private::process_linux::IntelPTSingleBufferTrace::GetIptTraceSize
size_t GetIptTraceSize() const
Definition: IntelPTSingleBufferTrace.cpp:200
lldb_private::process_linux::IntelPTSingleBufferTrace
This class wraps a single perf event collecting intel pt data in a single buffer.
Definition: IntelPTSingleBufferTrace.h:25
lldb_private::TraceIntelPTStartRequest
jLLDBTraceStart gdb-remote packet
Definition: TraceIntelPTGDBRemotePackets.h:33
IncludePerfEventParanoidMessageInError
static Error IncludePerfEventParanoidMessageInError(Error &&error)
Definition: IntelPTMultiCoreTrace.cpp:26
ProcessPOSIXLog.h
IsTotalBufferLimitReached
static bool IsTotalBufferLimitReached(ArrayRef< cpu_id_t > cores, const TraceIntelPTStartRequest &request)
Definition: IntelPTMultiCoreTrace.cpp:18
lldb_private::TraceIntelPTStartRequest::ipt_trace_size
uint64_t ipt_trace_size
Size in bytes to use for each thread's trace buffer.
Definition: TraceIntelPTGDBRemotePackets.h:35
lldb_private::process_linux::IntelPTSingleBufferTrace::Pause
llvm::Error Pause()
Pause the collection of this trace.
Definition: IntelPTSingleBufferTrace.cpp:204
uint32_t
lldb_private::process_linux::CreateContextSwitchTracePerfEvent
llvm::Expected< PerfEvent > CreateContextSwitchTracePerfEvent(lldb::cpu_id_t cpu_id, const PerfEvent *parent_perf_event=nullptr)
Create a perf event that tracks context switches on a cpu.
Definition: Perf.cpp:306
lldb_private::process_linux::IntelPTMultiCoreTrace
Definition: IntelPTMultiCoreTrace.h:23
lldb_private::NativeProcessProtocol
Definition: NativeProcessProtocol.h:48
lldb_private::TraceIntelPTStartRequest::process_buffer_size_limit
llvm::Optional< uint64_t > process_buffer_size_limit
Required when doing "process tracing".
Definition: TraceIntelPTGDBRemotePackets.h:48
lldb_private::TraceGetBinaryDataRequest::cpu_id
llvm::Optional< lldb::cpu_id_t > cpu_id
Optional core id if the data is related to a cpu core.
Definition: TraceGDBRemotePackets.h:157
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
Error
llvm::Error Error
Definition: UdtRecordCompleter.cpp:30
lldb
Definition: SBAddress.h:15
lldb::tid_t
uint64_t tid_t
Definition: lldb-types.h:86
lldb_private::TraceThreadState
Definition: TraceGDBRemotePackets.h:110