1 //===-- Perf.h --------------------------------------------------*- C++ -*-===// 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 /// \file 9 /// This file contains a thin wrapper of the perf_event_open API 10 /// and classes to handle the destruction of file descriptors 11 /// and mmap pointers. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLDB_SOURCE_PLUGINS_PROCESS_LINUX_PERF_H 16 #define LLDB_SOURCE_PLUGINS_PROCESS_LINUX_PERF_H 17 18 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" 19 #include "lldb/lldb-types.h" 20 21 #include "llvm/Support/Error.h" 22 23 #include <chrono> 24 #include <cstdint> 25 #include <linux/perf_event.h> 26 27 namespace lldb_private { 28 namespace process_linux { 29 namespace resource_handle { 30 31 /// Custom deleter for the pointer returned by \a mmap. 32 /// 33 /// This functor type is provided to \a unique_ptr to properly 34 /// unmap the region at destruction time. 35 class MmapDeleter { 36 public: 37 /// Construct new \a MmapDeleter. 38 /// 39 /// \param[in] bytes 40 /// Size of the mmap'ed region in bytes. 41 MmapDeleter(size_t bytes = 0) : m_bytes(bytes) {} 42 43 /// Unmap the mmap'ed region. 44 /// 45 /// If \a m_bytes==0 or \a ptr==nullptr, nothing is unmmapped. 46 /// 47 /// \param[in] ptr 48 /// pointer to the region to be unmmapped. 49 void operator()(void *ptr); 50 51 private: 52 /// Size of the mmap'ed region, in bytes, to be unmapped. 53 size_t m_bytes; 54 }; 55 56 /// Custom deleter for a file descriptor. 57 /// 58 /// This functor type is provided to \a unique_ptr to properly release 59 /// the resources associated with the file descriptor at destruction time. 60 class FileDescriptorDeleter { 61 public: 62 /// Close and free the memory associated with the file descriptor pointer. 63 /// 64 /// Effectively a no-op if \a ptr==nullptr or \a*ptr==-1. 65 /// 66 /// \param[in] ptr 67 /// Pointer to the file descriptor. 68 void operator()(long *ptr); 69 }; 70 71 using FileDescriptorUP = 72 std::unique_ptr<long, resource_handle::FileDescriptorDeleter>; 73 using MmapUP = std::unique_ptr<void, resource_handle::MmapDeleter>; 74 75 } // namespace resource_handle 76 77 /// Thin wrapper of the perf_event_open API. 78 /// 79 /// Exposes the metadata page and data and aux buffers of a perf event. 80 /// Handles the management of the event's file descriptor and mmap'ed 81 /// regions. 82 class PerfEvent { 83 public: 84 /// Create a new performance monitoring event via the perf_event_open syscall. 85 /// 86 /// The parameters are directly forwarded to a perf_event_open syscall, 87 /// for additional information on the parameters visit 88 /// https://man7.org/linux/man-pages/man2/perf_event_open.2.html. 89 /// 90 /// \param[in] attr 91 /// Configuration information for the event. 92 /// 93 /// \param[in] pid 94 /// The process to be monitored by the event. 95 /// 96 /// \param[in] cpu 97 /// The cpu to be monitored by the event. 98 /// 99 /// \param[in] group_fd 100 /// File descriptor of the group leader. 101 /// 102 /// \param[in] flags 103 /// Bitmask of additional configuration flags. 104 /// 105 /// \return 106 /// If the perf_event_open syscall was successful, a minimal \a PerfEvent 107 /// instance, or an \a llvm::Error otherwise. 108 static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, lldb::pid_t pid, 109 int cpu, int group_fd, 110 unsigned long flags); 111 112 /// Create a new performance monitoring event via the perf_event_open syscall 113 /// with "default" values for the cpu, group_fd and flags arguments. 114 /// 115 /// Convenience method to be used when the perf event requires minimal 116 /// configuration. It handles the default values of all other arguments. 117 /// 118 /// \param[in] attr 119 /// Configuration information for the event. 120 /// 121 /// \param[in] pid 122 /// The process to be monitored by the event. 123 static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, lldb::pid_t pid); 124 125 /// Mmap the metadata page and the data and aux buffers of the perf event and 126 /// expose them through \a PerfEvent::GetMetadataPage() , \a 127 /// PerfEvent::GetDataBuffer() and \a PerfEvent::GetAuxBuffer(). 128 /// 129 /// This uses mmap underneath, which means that the number of pages mmap'ed 130 /// must be less than the actual data available by the kernel. The metadata 131 /// page is always mmap'ed. 132 /// 133 /// Mmap is needed because the underlying data might be changed by the kernel 134 /// dynamically. 135 /// 136 /// \param[in] num_data_pages 137 /// Number of pages in the data buffer to mmap, must be a power of 2. 138 /// A value of 0 is useful for "dummy" events that only want to access 139 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 140 /// 141 /// \param[in] num_aux_pages 142 /// Number of pages in the aux buffer to mmap, must be a power of 2. 143 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 144 /// buffer. 145 /// 146 /// \return 147 /// \a llvm::Error::success if the mmap operations succeeded, 148 /// or an \a llvm::Error otherwise. 149 llvm::Error MmapMetadataAndBuffers(size_t num_data_pages, 150 size_t num_aux_pages); 151 152 /// Get the file descriptor associated with the perf event. 153 long GetFd() const; 154 155 /// Get the metadata page from the data section's mmap buffer. 156 /// 157 /// The metadata page is always mmap'ed, even when \a num_data_pages is 0. 158 /// 159 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 160 /// otherwise a failure might happen. 161 /// 162 /// \return 163 /// The data section's \a perf_event_mmap_page. 164 perf_event_mmap_page &GetMetadataPage() const; 165 166 /// Get the data buffer from the data section's mmap buffer. 167 /// 168 /// The data buffer is the region of the data section's mmap buffer where 169 /// perf sample data is located. 170 /// 171 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 172 /// otherwise a failure might happen. 173 /// 174 /// \return 175 /// \a ArrayRef<uint8_t> extending \a data_size bytes from \a data_offset. 176 llvm::ArrayRef<uint8_t> GetDataBuffer() const; 177 178 /// Get the AUX buffer. 179 /// 180 /// AUX buffer is a region for high-bandwidth data streams 181 /// such as IntelPT. This is separate from the metadata and data buffer. 182 /// 183 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 184 /// otherwise a failure might happen. 185 /// 186 /// \return 187 /// \a ArrayRef<uint8_t> extending \a aux_size bytes from \a aux_offset. 188 llvm::ArrayRef<uint8_t> GetAuxBuffer() const; 189 190 private: 191 /// Create new \a PerfEvent. 192 /// 193 /// \param[in] fd 194 /// File descriptor of the perf event. 195 PerfEvent(long fd) 196 : m_fd(new long(fd), resource_handle::FileDescriptorDeleter()), 197 m_metadata_data_base(), m_aux_base() {} 198 199 /// Wrapper for \a mmap to provide custom error messages. 200 /// 201 /// The parameters are directly forwarded to a \a mmap syscall, 202 /// for information on the parameters visit 203 /// https://man7.org/linux/man-pages/man2/mmap.2.html. 204 /// 205 /// The value of \a GetFd() is passed as the \a fd argument to \a mmap. 206 llvm::Expected<resource_handle::MmapUP> DoMmap(void *addr, size_t length, 207 int prot, int flags, 208 long int offset, 209 llvm::StringRef buffer_name); 210 211 /// Mmap the data buffer of the perf event. 212 /// 213 /// \param[in] num_data_pages 214 /// Number of pages in the data buffer to mmap, must be a power of 2. 215 /// A value of 0 is useful for "dummy" events that only want to access 216 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 217 llvm::Error MmapMetadataAndDataBuffer(size_t num_data_pages); 218 219 /// Mmap the aux buffer of the perf event. 220 /// 221 /// \param[in] num_aux_pages 222 /// Number of pages in the aux buffer to mmap, must be a power of 2. 223 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 224 /// buffer. 225 llvm::Error MmapAuxBuffer(size_t num_aux_pages); 226 227 /// The file descriptor representing the perf event. 228 resource_handle::FileDescriptorUP m_fd; 229 /// Metadata page and data section where perf samples are stored. 230 resource_handle::MmapUP m_metadata_data_base; 231 /// AUX buffer is a separate region for high-bandwidth data streams 232 /// such as IntelPT. 233 resource_handle::MmapUP m_aux_base; 234 }; 235 236 /// Load \a PerfTscConversionParameters from \a perf_event_mmap_page, if 237 /// available. 238 llvm::Expected<LinuxPerfZeroTscConversion> LoadPerfTscConversionParameters(); 239 240 } // namespace process_linux 241 } // namespace lldb_private 242 243 #endif // LLDB_SOURCE_PLUGINS_PROCESS_LINUX_PERF_H 244