LLDB  mainline
IntelPTSingleBufferTrace.cpp
Go to the documentation of this file.
1 //===-- IntelPTSingleBufferTrace.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 "lldb/Utility/Status.h"
13 #include "llvm/Support/Host.h"
14 #include "llvm/Support/MemoryBuffer.h"
15 #include <linux/perf_event.h>
16 #include <sstream>
17 #include <sys/syscall.h>
18 #include <unistd.h>
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 using namespace process_linux;
23 using namespace llvm;
24 
26  "/sys/bus/event_source/devices/intel_pt/type";
27 
28 const char *kPSBPeriodCapFile =
29  "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc";
30 
32  "/sys/bus/event_source/devices/intel_pt/caps/psb_periods";
33 
35  "/sys/bus/event_source/devices/intel_pt/format/psb_period";
36 
37 const char *kTSCBitOffsetFile =
38  "/sys/bus/event_source/devices/intel_pt/format/tsc";
39 
41  Hex = 0,
42  // 0 or 1
45  // a bit index file always starts with the prefix config: following by an int,
46  // which represents the offset of the perf_event_attr.config value where to
47  // store a given configuration.
49 };
50 
51 static Expected<uint32_t> ReadIntelPTConfigFile(const char *file,
52  IntelPTConfigFileType type) {
53  ErrorOr<std::unique_ptr<MemoryBuffer>> stream =
54  MemoryBuffer::getFileAsStream(file);
55 
56  if (!stream)
57  return createStringError(inconvertibleErrorCode(),
58  "Can't open the file '%s'", file);
59 
60  uint32_t value = 0;
61  StringRef text_buffer = stream.get()->getBuffer();
62 
63  if (type == BitOffset) {
64  const char *prefix = "config:";
65  if (!text_buffer.startswith(prefix))
66  return createStringError(inconvertibleErrorCode(),
67  "The file '%s' contents doesn't start with '%s'",
68  file, prefix);
69  text_buffer = text_buffer.substr(strlen(prefix));
70  }
71 
72  auto getRadix = [&]() {
73  switch (type) {
74  case Hex:
75  return 16;
76  case ZeroOne:
77  case Decimal:
78  case BitOffset:
79  return 10;
80  }
81  llvm_unreachable("Fully covered switch above!");
82  };
83 
84  auto createError = [&](const char *expected_value_message) {
85  return createStringError(
86  inconvertibleErrorCode(),
87  "The file '%s' has an invalid value. It should be %s.", file,
88  expected_value_message);
89  };
90 
91  if (text_buffer.trim().consumeInteger(getRadix(), value) ||
92  (type == ZeroOne && value != 0 && value != 1)) {
93  switch (type) {
94  case Hex:
95  return createError("an unsigned hexadecimal int");
96  case ZeroOne:
97  return createError("0 or 1");
98  case Decimal:
99  case BitOffset:
100  return createError("an unsigned decimal int");
101  }
102  }
103  return value;
104 }
105 
106 /// Return the Linux perf event type for Intel PT.
110 }
111 
112 static Error CheckPsbPeriod(size_t psb_period) {
113  Expected<uint32_t> cap =
115  if (!cap)
116  return cap.takeError();
117  if (*cap == 0)
118  return createStringError(inconvertibleErrorCode(),
119  "psb_period is unsupported in the system.");
120 
121  Expected<uint32_t> valid_values = ReadIntelPTConfigFile(
123  if (!valid_values)
124  return valid_values.takeError();
125 
126  if (valid_values.get() & (1 << psb_period))
127  return Error::success();
128 
129  std::ostringstream error;
130  // 0 is always a valid value
131  error << "Invalid psb_period. Valid values are: 0";
132  uint32_t mask = valid_values.get();
133  while (mask) {
134  int index = __builtin_ctz(mask);
135  if (index > 0)
136  error << ", " << index;
137  // clear the lowest bit
138  mask &= mask - 1;
139  }
140  error << ".";
141  return createStringError(inconvertibleErrorCode(), error.str().c_str());
142 }
143 
144 #ifdef PERF_ATTR_SIZE_VER5
145 static Expected<uint64_t>
146 GeneratePerfEventConfigValue(bool enable_tsc, Optional<uint64_t> psb_period) {
147  uint64_t config = 0;
148  // tsc is always supported
149  if (enable_tsc) {
150  if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
152  config |= 1 << *offset;
153  else
154  return offset.takeError();
155  }
156  if (psb_period) {
157  if (Error error = CheckPsbPeriod(*psb_period))
158  return std::move(error);
159 
160  if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
162  config |= *psb_period << *offset;
163  else
164  return offset.takeError();
165  }
166  return config;
167 }
168 
169 /// Create a \a perf_event_attr configured for
170 /// an IntelPT event.
171 ///
172 /// \return
173 /// A \a perf_event_attr if successful,
174 /// or an \a llvm::Error otherwise.
175 static Expected<perf_event_attr>
176 CreateIntelPTPerfEventConfiguration(bool enable_tsc,
177  llvm::Optional<uint64_t> psb_period) {
178  perf_event_attr attr;
179  memset(&attr, 0, sizeof(attr));
180  attr.size = sizeof(attr);
181  attr.exclude_kernel = 1;
182  attr.exclude_hv = 1;
183  attr.exclude_idle = 1;
184 
185  if (Expected<uint64_t> config_value =
186  GeneratePerfEventConfigValue(enable_tsc, psb_period))
187  attr.config = *config_value;
188  else
189  return config_value.takeError();
190 
191  if (Expected<uint32_t> intel_pt_type = GetIntelPTOSEventType())
192  attr.type = *intel_pt_type;
193  else
194  return intel_pt_type.takeError();
195 
196  return attr;
197 }
198 #endif
199 
200 size_t IntelPTSingleBufferTrace::GetIptTraceSize() const {
201  return m_perf_event.GetAuxBuffer().size();
202 }
203 
204 Error IntelPTSingleBufferTrace::Pause() {
205  return m_perf_event.DisableWithIoctl();
206 }
207 
208 Error IntelPTSingleBufferTrace::Resume() {
209  return m_perf_event.EnableWithIoctl();
210 }
211 
212 Expected<std::vector<uint8_t>> IntelPTSingleBufferTrace::GetIptTrace() {
213  // Disable the perf event to force a flush out of the CPU's internal buffer.
214  // Besides, we can guarantee that the CPU won't override any data as we are
215  // reading the buffer.
216  // The Intel documentation says:
217  //
218  // Packets are first buffered internally and then written out
219  // asynchronously. To collect packet output for postprocessing, a collector
220  // needs first to ensure that all packet data has been flushed from internal
221  // buffers. Software can ensure this by stopping packet generation by
222  // clearing IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in
223  // Section 35.2.7.2).
224  //
225  // This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as
226  // mentioned in the man page of perf_event_open.
227  return m_perf_event.GetReadOnlyAuxBuffer();
228 }
229 
230 Expected<IntelPTSingleBufferTrace> IntelPTSingleBufferTrace::Start(
231  const TraceIntelPTStartRequest &request, Optional<lldb::tid_t> tid,
232  Optional<cpu_id_t> cpu_id, bool disabled, Optional<int> cgroup_fd) {
233 #ifndef PERF_ATTR_SIZE_VER5
234  return createStringError(inconvertibleErrorCode(),
235  "Intel PT Linux perf event not supported");
236 #else
237  Log *log = GetLog(POSIXLog::Trace);
238 
239  LLDB_LOG(log, "Will start tracing thread id {0} and cpu id {1}", tid, cpu_id);
240 
241  if (__builtin_popcount(request.ipt_trace_size) != 1 ||
242  request.ipt_trace_size < 4096) {
243  return createStringError(
244  inconvertibleErrorCode(),
245  "The intel pt trace size must be a power of 2 greater than or equal to "
246  "4096 (2^12) bytes. It was %" PRIu64 ".",
247  request.ipt_trace_size);
248  }
249  uint64_t page_size = getpagesize();
250  uint64_t aux_buffer_numpages = static_cast<uint64_t>(llvm::PowerOf2Floor(
251  (request.ipt_trace_size + page_size - 1) / page_size));
252 
253  Expected<perf_event_attr> attr = CreateIntelPTPerfEventConfiguration(
254  request.enable_tsc, request.psb_period.map([](int value) {
255  return static_cast<uint64_t>(value);
256  }));
257  if (!attr)
258  return attr.takeError();
259  attr->disabled = disabled;
260 
261  LLDB_LOG(log, "Will create intel pt trace buffer of size {0}",
262  request.ipt_trace_size);
263  unsigned long flags = 0;
264  if (cgroup_fd) {
265  tid = *cgroup_fd;
266  flags |= PERF_FLAG_PID_CGROUP;
267  }
268 
269  if (Expected<PerfEvent> perf_event =
270  PerfEvent::Init(*attr, tid, cpu_id, -1, flags)) {
271  if (Error mmap_err = perf_event->MmapMetadataAndBuffers(
272  /*num_data_pages=*/0, aux_buffer_numpages,
273  /*data_buffer_write=*/true)) {
274  return std::move(mmap_err);
275  }
276  return IntelPTSingleBufferTrace(std::move(*perf_event));
277  } else {
278  return perf_event.takeError();
279  }
280 #endif
281 }
282 
283 const PerfEvent &IntelPTSingleBufferTrace::GetPerfEvent() const {
284  return m_perf_event;
285 }
llvm
Definition: Debugger.h:50
kPSBPeriodBitOffsetFile
const char * kPSBPeriodBitOffsetFile
Definition: IntelPTSingleBufferTrace.cpp:34
kPSBPeriodCapFile
const char * kPSBPeriodCapFile
Definition: IntelPTSingleBufferTrace.cpp:28
kOSEventIntelPTTypeFile
const char * kOSEventIntelPTTypeFile
Definition: IntelPTSingleBufferTrace.cpp:25
Hex
@ Hex
Definition: IntelPTSingleBufferTrace.cpp:41
lldb_private::process_linux::PerfEvent
Thin wrapper of the perf_event_open API.
Definition: Perf.h:80
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb_private::process_linux::IntelPTSingleBufferTrace
This class wraps a single perf event collecting intel pt data in a single buffer.
Definition: IntelPTSingleBufferTrace.h:25
Decimal
@ Decimal
Definition: IntelPTSingleBufferTrace.cpp:44
StreamString.h
lldb_private::TraceIntelPTStartRequest::psb_period
llvm::Optional< uint64_t > psb_period
PSB packet period.
Definition: TraceIntelPTGDBRemotePackets.h:41
lldb_private::TraceIntelPTStartRequest
jLLDBTraceStart gdb-remote packet
Definition: TraceIntelPTGDBRemotePackets.h:33
ProcessPOSIXLog.h
BitOffset
@ BitOffset
Definition: IntelPTSingleBufferTrace.cpp:48
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
ZeroOne
@ ZeroOne
Definition: IntelPTSingleBufferTrace.cpp:43
uint32_t
IntelPTConfigFileType
IntelPTConfigFileType
Definition: IntelPTSingleBufferTrace.cpp:40
CheckPsbPeriod
static Error CheckPsbPeriod(size_t psb_period)
Definition: IntelPTSingleBufferTrace.cpp:112
kTSCBitOffsetFile
const char * kTSCBitOffsetFile
Definition: IntelPTSingleBufferTrace.cpp:37
LLDB_LOG
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:336
lldb_private::TraceIntelPTStartRequest::enable_tsc
bool enable_tsc
Whether to enable TSC.
Definition: TraceIntelPTGDBRemotePackets.h:38
kPSBPeriodValidValuesFile
const char * kPSBPeriodValidValuesFile
Definition: IntelPTSingleBufferTrace.cpp:31
Status.h
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
IntelPTSingleBufferTrace.h
lldb_private::Log
Definition: Log.h:115
lldb_private::process_linux::GetIntelPTOSEventType
llvm::Expected< uint32_t > GetIntelPTOSEventType()
Return the Linux perf event type for Intel PT.
Definition: IntelPTSingleBufferTrace.cpp:107
ReadIntelPTConfigFile
static Expected< uint32_t > ReadIntelPTConfigFile(const char *file, IntelPTConfigFileType type)
Definition: IntelPTSingleBufferTrace.cpp:51
lldb_private::GetLog
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:308
lldb
Definition: SBAddress.h:15