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 enum class CollectionState { 102 Enabled, 103 Disabled, 104 }; 105 106 public: 107 /// Create a new performance monitoring event via the perf_event_open syscall. 108 /// 109 /// The parameters are directly forwarded to a perf_event_open syscall, 110 /// for additional information on the parameters visit 111 /// https://man7.org/linux/man-pages/man2/perf_event_open.2.html. 112 /// 113 /// \param[in] attr 114 /// Configuration information for the event. 115 /// 116 /// \param[in] pid 117 /// The process or thread to be monitored by the event. If \b None, then 118 /// all processes and threads are monitored. 119 /// 120 /// \param[in] cpu 121 /// The cpu to be monitored by the event. If \b None, then all cpus are 122 /// monitored. 123 /// 124 /// \param[in] group_fd 125 /// File descriptor of the group leader. If \b None, then this perf_event 126 /// doesn't belong to a preexisting group. 127 /// 128 /// \param[in] flags 129 /// Bitmask of additional configuration flags. 130 /// 131 /// \return 132 /// If the perf_event_open syscall was successful, a minimal \a PerfEvent 133 /// instance, or an \a llvm::Error otherwise. 134 static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, 135 llvm::Optional<lldb::pid_t> pid, 136 llvm::Optional<lldb::core_id_t> cpu, 137 llvm::Optional<int> group_fd, 138 unsigned long flags); 139 140 /// Create a new performance monitoring event via the perf_event_open syscall 141 /// with "default" values for the cpu, group_fd and flags arguments. 142 /// 143 /// Convenience method to be used when the perf event requires minimal 144 /// configuration. It handles the default values of all other arguments. 145 /// 146 /// \param[in] attr 147 /// Configuration information for the event. 148 /// 149 /// \param[in] pid 150 /// The process or thread to be monitored by the event. If \b None, then 151 /// all threads and processes are monitored. 152 static llvm::Expected<PerfEvent> 153 Init(perf_event_attr &attr, llvm::Optional<lldb::pid_t> pid, 154 llvm::Optional<lldb::core_id_t> core = llvm::None); 155 156 /// Mmap the metadata page and the data and aux buffers of the perf event and 157 /// expose them through \a PerfEvent::GetMetadataPage() , \a 158 /// PerfEvent::GetDataBuffer() and \a PerfEvent::GetAuxBuffer(). 159 /// 160 /// This uses mmap underneath, which means that the number of pages mmap'ed 161 /// must be less than the actual data available by the kernel. The metadata 162 /// page is always mmap'ed. 163 /// 164 /// Mmap is needed because the underlying data might be changed by the kernel 165 /// dynamically. 166 /// 167 /// \param[in] num_data_pages 168 /// Number of pages in the data buffer to mmap, must be a power of 2. 169 /// A value of 0 is useful for "dummy" events that only want to access 170 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 171 /// 172 /// \param[in] num_aux_pages 173 /// Number of pages in the aux buffer to mmap, must be a power of 2. 174 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 175 /// buffer. 176 /// 177 /// \return 178 /// \a llvm::Error::success if the mmap operations succeeded, 179 /// or an \a llvm::Error otherwise. 180 llvm::Error MmapMetadataAndBuffers(size_t num_data_pages, 181 size_t num_aux_pages); 182 183 /// Get the file descriptor associated with the perf event. 184 long GetFd() const; 185 186 /// Get the metadata page from the data section's mmap buffer. 187 /// 188 /// The metadata page is always mmap'ed, even when \a num_data_pages is 0. 189 /// 190 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 191 /// otherwise a failure might happen. 192 /// 193 /// \return 194 /// The data section's \a perf_event_mmap_page. 195 perf_event_mmap_page &GetMetadataPage() const; 196 197 /// Get the data buffer from the data section's mmap buffer. 198 /// 199 /// The data buffer is the region of the data section's mmap buffer where 200 /// perf sample data is located. 201 /// 202 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 203 /// otherwise a failure might happen. 204 /// 205 /// \return 206 /// \a ArrayRef<uint8_t> extending \a data_size bytes from \a data_offset. 207 llvm::ArrayRef<uint8_t> GetDataBuffer() const; 208 209 /// Get the AUX buffer. 210 /// 211 /// AUX buffer is a region for high-bandwidth data streams 212 /// such as IntelPT. This is separate from the metadata and data buffer. 213 /// 214 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 215 /// otherwise a failure might happen. 216 /// 217 /// \return 218 /// \a ArrayRef<uint8_t> extending \a aux_size bytes from \a aux_offset. 219 llvm::ArrayRef<uint8_t> GetAuxBuffer() const; 220 221 /// Read the aux buffer managed by this perf event. To ensure that the 222 /// data is up-to-date and is not corrupted by read-write race conditions, the 223 /// underlying perf_event is paused during read, and later it's returned to 224 /// its initial state. The returned data will be linear, i.e. it will fix the 225 /// circular wrapping the might exist int he buffer. 226 /// 227 /// \param[in] offset 228 /// Offset of the data to read. 229 /// 230 /// \param[in] size 231 /// Number of bytes to read. 232 /// 233 /// \return 234 /// A vector with the requested binary data. The vector will have the 235 /// size of the requested \a size. Non-available positions will be 236 /// filled with zeroes. 237 llvm::Expected<std::vector<uint8_t>> 238 ReadFlushedOutAuxCyclicBuffer(size_t offset, size_t size); 239 240 /// Use the ioctl API to disable the perf event and all the events in its 241 /// group. This doesn't terminate the perf event. 242 /// 243 /// This is no-op if the perf event is already disabled. 244 /// 245 /// \return 246 /// An Error if the perf event couldn't be disabled. 247 llvm::Error DisableWithIoctl(); 248 249 /// Use the ioctl API to enable the perf event and all the events in its 250 /// group. 251 /// 252 /// This is no-op if the perf event is already enabled. 253 /// 254 /// \return 255 /// An Error if the perf event couldn't be enabled. 256 llvm::Error EnableWithIoctl(); 257 258 /// \return 259 /// The size in bytes of the section of the data buffer that has effective 260 /// data. 261 size_t GetEffectiveDataBufferSize() const; 262 263 private: 264 /// Create new \a PerfEvent. 265 /// 266 /// \param[in] fd 267 /// File descriptor of the perf event. 268 /// 269 /// \param[in] initial_state 270 /// Initial collection state configured for this perf_event. 271 PerfEvent(long fd, CollectionState initial_state) 272 : m_fd(new long(fd), resource_handle::FileDescriptorDeleter()), 273 m_collection_state(initial_state) {} 274 275 /// Wrapper for \a mmap to provide custom error messages. 276 /// 277 /// The parameters are directly forwarded to a \a mmap syscall, 278 /// for information on the parameters visit 279 /// https://man7.org/linux/man-pages/man2/mmap.2.html. 280 /// 281 /// The value of \a GetFd() is passed as the \a fd argument to \a mmap. 282 llvm::Expected<resource_handle::MmapUP> DoMmap(void *addr, size_t length, 283 int prot, int flags, 284 long int offset, 285 llvm::StringRef buffer_name); 286 287 /// Mmap the data buffer of the perf event. 288 /// 289 /// \param[in] num_data_pages 290 /// Number of pages in the data buffer to mmap, must be a power of 2. 291 /// A value of 0 is useful for "dummy" events that only want to access 292 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 293 llvm::Error MmapMetadataAndDataBuffer(size_t num_data_pages); 294 295 /// Mmap the aux buffer of the perf event. 296 /// 297 /// \param[in] num_aux_pages 298 /// Number of pages in the aux buffer to mmap, must be a power of 2. 299 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 300 /// buffer. 301 llvm::Error MmapAuxBuffer(size_t num_aux_pages); 302 303 /// The file descriptor representing the perf event. 304 resource_handle::FileDescriptorUP m_fd; 305 /// Metadata page and data section where perf samples are stored. 306 resource_handle::MmapUP m_metadata_data_base; 307 /// AUX buffer is a separate region for high-bandwidth data streams 308 /// such as IntelPT. 309 resource_handle::MmapUP m_aux_base; 310 /// The state of the underlying perf_event. 311 CollectionState m_collection_state; 312 }; 313 314 /// Load \a PerfTscConversionParameters from \a perf_event_mmap_page, if 315 /// available. 316 llvm::Expected<LinuxPerfZeroTscConversion> LoadPerfTscConversionParameters(); 317 318 } // namespace process_linux 319 } // namespace lldb_private 320 321 #endif // LLDB_SOURCE_PLUGINS_PROCESS_LINUX_PERF_H 322