12#include "llvm/Support/FormatVariadic.h" 
   13#include "llvm/Support/MathExtras.h" 
   14#include "llvm/Support/MemoryBuffer.h" 
   15#include <linux/version.h> 
   18#include <sys/syscall.h> 
   25Expected<LinuxPerfZeroTscConversion>
 
   27#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) 
   30  memset(&attr, 0, 
sizeof(attr));
 
   31  attr.size = 
sizeof(attr);
 
   32  attr.type = PERF_TYPE_SOFTWARE;
 
   33  attr.config = PERF_COUNT_SW_DUMMY;
 
   37    return perf_event.takeError();
 
   39          perf_event->MmapMetadataAndBuffers(0,
 
   42    return std::move(mmap_err);
 
   44  perf_event_mmap_page &mmap_metada = perf_event->GetMetadataPage();
 
   45  if (mmap_metada.cap_user_time && mmap_metada.cap_user_time_zero) {
 
   47        mmap_metada.time_mult, mmap_metada.time_shift, {mmap_metada.time_zero}};
 
   50        !mmap_metada.cap_user_time ? 
"cap_user_time" : 
"cap_user_time_zero";
 
   52        llvm::formatv(
"Can't get TSC to real time conversion values. " 
   53                      "perf_event capability '{0}' not supported.",
 
   55    return llvm::createStringError(llvm::inconvertibleErrorCode(), err_msg);
 
   58  std::string err_msg = 
"PERF_COUNT_SW_DUMMY requires Linux 3.12";
 
   59  return llvm::createStringError(llvm::inconvertibleErrorCode(), err_msg);
 
 
   74  std::default_delete<long>()(ptr);
 
 
   78                                          std::optional<lldb::pid_t> pid,
 
   79                                          std::optional<lldb::cpu_id_t> cpu,
 
   80                                          std::optional<long> group_fd,
 
   81                                          unsigned long flags) {
 
   83  long fd = syscall(SYS_perf_event_open, &attr, pid.value_or(-1),
 
   84                    cpu.value_or(-1), group_fd.value_or(-1), flags);
 
   87        llvm::formatv(
"perf event syscall failed: {0}", std::strerror(errno));
 
   88    return llvm::createStringError(llvm::inconvertibleErrorCode(), err_msg);
 
 
   94                                          std::optional<lldb::pid_t> pid,
 
   95                                          std::optional<lldb::cpu_id_t> cpu) {
 
   96  return Init(attr, pid, cpu, -1, 0);
 
 
   99llvm::Expected<resource_handle::MmapUP>
 
  101                  long int offset, llvm::StringRef buffer_name) {
 
  103  auto mmap_result = ::mmap(addr, length, prot, flags, 
GetFd(), offset);
 
  105  if (mmap_result == MAP_FAILED) {
 
  106    std::string err_msg =
 
  107        llvm::formatv(
"perf event mmap allocation failed for {0}: {1}",
 
  108                      buffer_name, std::strerror(errno));
 
 
  115                                                 bool data_buffer_write) {
 
  116  size_t mmap_size = (num_data_pages + 1) * getpagesize();
 
  117  if (Expected<resource_handle::MmapUP> mmap_metadata_data = 
DoMmap(
 
  119          MAP_SHARED, 0, 
"metadata and data buffer")) {
 
  121    return Error::success();
 
  123    return mmap_metadata_data.takeError();
 
 
  127#ifndef PERF_ATTR_SIZE_VER5 
  129                           "Intel PT Linux perf event not supported");
 
  131  if (num_aux_pages == 0)
 
  132    return Error::success();
 
  136  metadata_page.aux_offset =
 
  137      metadata_page.data_offset + metadata_page.data_size;
 
  138  metadata_page.aux_size = num_aux_pages * getpagesize();
 
  140  if (Expected<resource_handle::MmapUP> mmap_aux =
 
  142                 metadata_page.aux_offset, 
"aux buffer")) {
 
  144    return Error::success();
 
  146    return mmap_aux.takeError();
 
 
  151                                              size_t num_aux_pages,
 
  152                                              bool data_buffer_write) {
 
  153  if (num_data_pages != 0 && !isPowerOf2_64(num_data_pages))
 
  154    return llvm::createStringError(
 
  155        llvm::inconvertibleErrorCode(),
 
  156        llvm::formatv(
"Number of data pages must be a power of 2, got: {0}",
 
  158  if (num_aux_pages != 0 && !isPowerOf2_64(num_aux_pages))
 
  159    return llvm::createStringError(
 
  160        llvm::inconvertibleErrorCode(),
 
  161        llvm::formatv(
"Number of aux pages must be a power of 2, got: {0}",
 
  167  return Error::success();
 
 
  177#ifndef PERF_ATTR_SIZE_VER5 
  178  llvm_unreachable(
"Intel PT Linux perf event not supported");
 
  182              mmap_metadata.data_offset,
 
  183          static_cast<size_t>(mmap_metadata.data_size)};
 
 
  188#ifndef PERF_ATTR_SIZE_VER5 
  189  llvm_unreachable(
"Intel PT Linux perf event not supported");
 
  192  return {
reinterpret_cast<uint8_t *
>(
m_aux_base.get()),
 
  193          static_cast<size_t>(mmap_metadata.aux_size)};
 
 
  203#ifndef PERF_ATTR_SIZE_VER5 
  205                           "Intel PT Linux perf event not supported");
 
  209    return std::move(err);
 
  221  uint64_t data_head = mmap_metadata.data_head;
 
  222  uint64_t data_size = mmap_metadata.data_size;
 
  223  std::vector<uint8_t> output;
 
  224  output.reserve(data.size());
 
  226  if (data_head > data_size) {
 
  227    uint64_t actual_data_head = data_head % data_size;
 
  229    output.insert(output.end(), data.begin() + actual_data_head, data.end());
 
  231    output.insert(output.end(), data.begin(), data.begin() + actual_data_head);
 
  234    output.insert(output.end(), data.begin(), data.begin() + data_head);
 
  239      return std::move(err);
 
 
  252#ifndef PERF_ATTR_SIZE_VER5 
  254                           "Intel PT Linux perf event not supported");
 
  258    return std::move(err);
 
  263  uint64_t aux_head = mmap_metadata.aux_head;
 
  264  std::vector<uint8_t> output;
 
  265  output.reserve(data.size());
 
  279  output.insert(output.end(), data.begin() + aux_head, data.end());
 
  280  output.insert(output.end(), data.begin(), data.begin() + aux_head);
 
  284      return std::move(err);
 
 
  293    return Error::success();
 
  295  if (ioctl(*
m_fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) < 0)
 
  297                             "Can't disable perf event. %s",
 
  298                             std::strerror(errno));
 
  301  return Error::success();
 
 
  308    return Error::success();
 
  310  if (ioctl(*
m_fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) < 0)
 
  312                             "Can't enable perf event. %s",
 
  313                             std::strerror(errno));
 
  316  return Error::success();
 
 
  320#ifndef PERF_ATTR_SIZE_VER5 
  321  llvm_unreachable(
"Intel PT Linux perf event not supported");
 
  324  if (mmap_metadata.data_head < mmap_metadata.data_size)
 
  325    return mmap_metadata.data_head;
 
  327    return mmap_metadata.data_size; 
 
 
  335#ifndef PERF_ATTR_SIZE_VER5 
  337                           "Intel PT Linux perf event not supported");
 
  339  perf_event_attr attr;
 
  340  memset(&attr, 0, 
sizeof(attr));
 
  341  attr.size = 
sizeof(attr);
 
  342  attr.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_TIME;
 
  343  attr.type = PERF_TYPE_SOFTWARE;
 
  344  attr.context_switch = 1;
 
  345  attr.exclude_kernel = 1;
 
  346  attr.sample_id_all = 1;
 
  348  attr.disabled = parent_perf_event ? !parent_perf_event->
IsEnabled() : 
false;
 
  358  uint64_t data_buffer_size = 32768;
 
  359  uint64_t data_buffer_numpages = data_buffer_size / getpagesize();
 
  361  LLDB_LOG(log, 
"Will create context switch trace buffer of size {0}",
 
  364  std::optional<long> group_fd;
 
  365  if (parent_perf_event)
 
  366    group_fd = parent_perf_event->
GetFd();
 
  369          attr, std::nullopt, cpu_id, group_fd, 0)) {
 
  370    if (Error mmap_err = perf_event->MmapMetadataAndBuffers(
 
  371            data_buffer_numpages, 0, 
false)) {
 
  372      return std::move(mmap_err);
 
  376    return perf_event.takeError();
 
 
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
This file contains a thin wrapper of the perf_event_open API and classes to handle the destruction of...
static llvm::Error createStringError(const char *format, Args &&...args)
Thin wrapper of the perf_event_open API.
llvm::Error MmapAuxBuffer(size_t num_aux_pages)
Mmap the aux buffer of the perf event.
llvm::Expected< std::vector< uint8_t > > GetReadOnlyAuxBuffer()
Read the aux buffer managed by this perf event assuming it was configured with PROT_READ permissions ...
resource_handle::MmapUP m_metadata_data_base
Metadata page and data section where perf samples are stored.
bool m_enabled
The state of the underlying perf_event.
llvm::Expected< std::vector< uint8_t > > GetReadOnlyDataBuffer()
Read the data buffer managed by this perf even assuming it was configured with PROT_READ permissions ...
perf_event_mmap_page & GetMetadataPage() const
Get the metadata page from the data section's mmap buffer.
resource_handle::MmapUP m_aux_base
AUX buffer is a separate region for high-bandwidth data streams such as IntelPT.
llvm::Error DisableWithIoctl()
Use the ioctl API to disable the perf event and all the events in its group.
size_t GetEffectiveDataBufferSize() const
llvm::Error MmapMetadataAndBuffers(size_t num_data_pages, size_t num_aux_pages, bool data_buffer_write)
Mmap the metadata page and the data and aux buffers of the perf event and expose them through PerfEve...
resource_handle::FileDescriptorUP m_fd
The file descriptor representing the perf event.
llvm::Error EnableWithIoctl()
Use the ioctl API to enable the perf event and all the events in its group.
long GetFd() const
Get the file descriptor associated with the perf event.
llvm::Error MmapMetadataAndDataBuffer(size_t num_data_pages, bool data_buffer_write)
Mmap the data buffer of the perf event.
llvm::ArrayRef< uint8_t > GetAuxBuffer() const
Get the AUX buffer.
llvm::Expected< resource_handle::MmapUP > DoMmap(void *addr, size_t length, int prot, int flags, long int offset, llvm::StringRef buffer_name)
Wrapper for mmap to provide custom error messages.
llvm::ArrayRef< uint8_t > GetDataBuffer() const
Get the data buffer from the data section's mmap buffer.
static llvm::Expected< PerfEvent > Init(perf_event_attr &attr, std::optional< lldb::pid_t > pid, std::optional< lldb::cpu_id_t > cpu, std::optional< long > group_fd, unsigned long flags)
Create a new performance monitoring event via the perf_event_open syscall.
PerfEvent(long fd, bool enabled)
Create new PerfEvent.
void operator()(long *ptr)
Close and free the memory associated with the file descriptor pointer.
void operator()(void *ptr)
Unmap the mmap'ed region.
size_t m_bytes
Size of the mmap'ed region, in bytes, to be unmapped.
std::unique_ptr< void, resource_handle::MmapDeleter > MmapUP
llvm::Expected< LinuxPerfZeroTscConversion > LoadPerfTscConversionParameters()
Load PerfTscConversionParameters from perf_event_mmap_page, if available.
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.
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
jLLDBTraceGetState gdb-remote packet