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 /// Read data from a cyclic buffer 78 /// 79 /// \param[in] [out] buf 80 /// Destination buffer, the buffer will be truncated to written size. 81 /// 82 /// \param[in] src 83 /// Source buffer which must be a cyclic buffer. 84 /// 85 /// \param[in] src_cyc_index 86 /// The index pointer (start of the valid data in the cyclic 87 /// buffer). 88 /// 89 /// \param[in] offset 90 /// The offset to begin reading the data in the cyclic buffer. 91 void ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst, 92 llvm::ArrayRef<uint8_t> src, size_t src_cyc_index, 93 size_t offset); 94 95 /// Thin wrapper of the perf_event_open API. 96 /// 97 /// Exposes the metadata page and data and aux buffers of a perf event. 98 /// Handles the management of the event's file descriptor and mmap'ed 99 /// regions. 100 class PerfEvent { 101 public: 102 /// Create a new performance monitoring event via the perf_event_open syscall. 103 /// 104 /// The parameters are directly forwarded to a perf_event_open syscall, 105 /// for additional information on the parameters visit 106 /// https://man7.org/linux/man-pages/man2/perf_event_open.2.html. 107 /// 108 /// \param[in] attr 109 /// Configuration information for the event. 110 /// 111 /// \param[in] pid 112 /// The process or thread to be monitored by the event. If \b None, then 113 /// all processes and threads are monitored. 114 /// 115 /// \param[in] cpu 116 /// The cpu to be monitored by the event. If \b None, then all cpus are 117 /// monitored. 118 /// 119 /// \param[in] group_fd 120 /// File descriptor of the group leader. If \b None, then this perf_event 121 /// doesn't belong to a preexisting group. 122 /// 123 /// \param[in] flags 124 /// Bitmask of additional configuration flags. 125 /// 126 /// \return 127 /// If the perf_event_open syscall was successful, a minimal \a PerfEvent 128 /// instance, or an \a llvm::Error otherwise. 129 static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, 130 llvm::Optional<lldb::pid_t> pid, 131 llvm::Optional<lldb::core_id_t> cpu, 132 llvm::Optional<int> group_fd, 133 unsigned long flags); 134 135 /// Create a new performance monitoring event via the perf_event_open syscall 136 /// with "default" values for the cpu, group_fd and flags arguments. 137 /// 138 /// Convenience method to be used when the perf event requires minimal 139 /// configuration. It handles the default values of all other arguments. 140 /// 141 /// \param[in] attr 142 /// Configuration information for the event. 143 /// 144 /// \param[in] pid 145 /// The process or thread to be monitored by the event. If \b None, then 146 /// all threads and processes are monitored. 147 static llvm::Expected<PerfEvent> 148 Init(perf_event_attr &attr, llvm::Optional<lldb::pid_t> pid, 149 llvm::Optional<lldb::core_id_t> core = llvm::None); 150 151 /// Mmap the metadata page and the data and aux buffers of the perf event and 152 /// expose them through \a PerfEvent::GetMetadataPage() , \a 153 /// PerfEvent::GetDataBuffer() and \a PerfEvent::GetAuxBuffer(). 154 /// 155 /// This uses mmap underneath, which means that the number of pages mmap'ed 156 /// must be less than the actual data available by the kernel. The metadata 157 /// page is always mmap'ed. 158 /// 159 /// Mmap is needed because the underlying data might be changed by the kernel 160 /// dynamically. 161 /// 162 /// \param[in] num_data_pages 163 /// Number of pages in the data buffer to mmap, must be a power of 2. 164 /// A value of 0 is useful for "dummy" events that only want to access 165 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 166 /// 167 /// \param[in] num_aux_pages 168 /// Number of pages in the aux buffer to mmap, must be a power of 2. 169 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 170 /// buffer. 171 /// 172 /// \return 173 /// \a llvm::Error::success if the mmap operations succeeded, 174 /// or an \a llvm::Error otherwise. 175 llvm::Error MmapMetadataAndBuffers(size_t num_data_pages, 176 size_t num_aux_pages); 177 178 /// Get the file descriptor associated with the perf event. 179 long GetFd() const; 180 181 /// Get the metadata page from the data section's mmap buffer. 182 /// 183 /// The metadata page is always mmap'ed, even when \a num_data_pages is 0. 184 /// 185 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 186 /// otherwise a failure might happen. 187 /// 188 /// \return 189 /// The data section's \a perf_event_mmap_page. 190 perf_event_mmap_page &GetMetadataPage() const; 191 192 /// Get the data buffer from the data section's mmap buffer. 193 /// 194 /// The data buffer is the region of the data section's mmap buffer where 195 /// perf sample data is located. 196 /// 197 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 198 /// otherwise a failure might happen. 199 /// 200 /// \return 201 /// \a ArrayRef<uint8_t> extending \a data_size bytes from \a data_offset. 202 llvm::ArrayRef<uint8_t> GetDataBuffer() const; 203 204 /// Get the AUX buffer. 205 /// 206 /// AUX buffer is a region for high-bandwidth data streams 207 /// such as IntelPT. This is separate from the metadata and data buffer. 208 /// 209 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 210 /// otherwise a failure might happen. 211 /// 212 /// \return 213 /// \a ArrayRef<uint8_t> extending \a aux_size bytes from \a aux_offset. 214 llvm::ArrayRef<uint8_t> GetAuxBuffer() const; 215 216 /// Use the ioctl API to disable the perf event. This doesn't terminate the 217 /// perf event. 218 /// 219 /// \return 220 /// An Error if the perf event couldn't be disabled. 221 llvm::Error DisableWithIoctl() const; 222 223 /// Use the ioctl API to enable the perf event. 224 /// 225 /// \return 226 /// An Error if the perf event couldn't be enabled. 227 llvm::Error EnableWithIoctl() const; 228 229 private: 230 /// Create new \a PerfEvent. 231 /// 232 /// \param[in] fd 233 /// File descriptor of the perf event. 234 PerfEvent(long fd) 235 : m_fd(new long(fd), resource_handle::FileDescriptorDeleter()), 236 m_metadata_data_base(), m_aux_base() {} 237 238 /// Wrapper for \a mmap to provide custom error messages. 239 /// 240 /// The parameters are directly forwarded to a \a mmap syscall, 241 /// for information on the parameters visit 242 /// https://man7.org/linux/man-pages/man2/mmap.2.html. 243 /// 244 /// The value of \a GetFd() is passed as the \a fd argument to \a mmap. 245 llvm::Expected<resource_handle::MmapUP> DoMmap(void *addr, size_t length, 246 int prot, int flags, 247 long int offset, 248 llvm::StringRef buffer_name); 249 250 /// Mmap the data buffer of the perf event. 251 /// 252 /// \param[in] num_data_pages 253 /// Number of pages in the data buffer to mmap, must be a power of 2. 254 /// A value of 0 is useful for "dummy" events that only want to access 255 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 256 llvm::Error MmapMetadataAndDataBuffer(size_t num_data_pages); 257 258 /// Mmap the aux buffer of the perf event. 259 /// 260 /// \param[in] num_aux_pages 261 /// Number of pages in the aux buffer to mmap, must be a power of 2. 262 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 263 /// buffer. 264 llvm::Error MmapAuxBuffer(size_t num_aux_pages); 265 266 /// The file descriptor representing the perf event. 267 resource_handle::FileDescriptorUP m_fd; 268 /// Metadata page and data section where perf samples are stored. 269 resource_handle::MmapUP m_metadata_data_base; 270 /// AUX buffer is a separate region for high-bandwidth data streams 271 /// such as IntelPT. 272 resource_handle::MmapUP m_aux_base; 273 }; 274 275 /// Load \a PerfTscConversionParameters from \a perf_event_mmap_page, if 276 /// available. 277 llvm::Expected<LinuxPerfZeroTscConversion> LoadPerfTscConversionParameters(); 278 279 } // namespace process_linux 280 } // namespace lldb_private 281 282 #endif // LLDB_SOURCE_PLUGINS_PROCESS_LINUX_PERF_H 283