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 #include "llvm/Support/Error.h" 21 #include <chrono> 22 #include <cstdint> 23 #include <linux/perf_event.h> 24 25 namespace lldb_private { 26 namespace process_linux { 27 namespace resource_handle { 28 29 /// Custom deleter for the pointer returned by \a mmap. 30 /// 31 /// This functor type is provided to \a unique_ptr to properly 32 /// unmap the region at destruction time. 33 class MmapDeleter { 34 public: 35 /// Construct new \a MmapDeleter. 36 /// 37 /// \param[in] bytes 38 /// Size of the mmap'ed region in bytes. 39 MmapDeleter(size_t bytes = 0) : m_bytes(bytes) {} 40 41 /// Unmap the mmap'ed region. 42 /// 43 /// If \a m_bytes==0 or \a ptr==nullptr, nothing is unmmapped. 44 /// 45 /// \param[in] ptr 46 /// pointer to the region to be unmmapped. 47 void operator()(void *ptr); 48 49 private: 50 /// Size of the mmap'ed region, in bytes, to be unmapped. 51 size_t m_bytes; 52 }; 53 54 /// Custom deleter for a file descriptor. 55 /// 56 /// This functor type is provided to \a unique_ptr to properly release 57 /// the resources associated with the file descriptor at destruction time. 58 class FileDescriptorDeleter { 59 public: 60 /// Close and free the memory associated with the file descriptor pointer. 61 /// 62 /// Effectively a no-op if \a ptr==nullptr or \a*ptr==-1. 63 /// 64 /// \param[in] ptr 65 /// Pointer to the file descriptor. 66 void operator()(long *ptr); 67 }; 68 69 using FileDescriptorUP = 70 std::unique_ptr<long, resource_handle::FileDescriptorDeleter>; 71 using MmapUP = std::unique_ptr<void, resource_handle::MmapDeleter>; 72 73 } // namespace resource_handle 74 75 /// Thin wrapper of the perf_event_open API. 76 /// 77 /// Exposes the metadata page and data and aux buffers of a perf event. 78 /// Handles the management of the event's file descriptor and mmap'ed 79 /// regions. 80 class PerfEvent { 81 public: 82 /// Create a new performance monitoring event via the perf_event_open syscall. 83 /// 84 /// The parameters are directly forwarded to a perf_event_open syscall, 85 /// for additional information on the parameters visit 86 /// https://man7.org/linux/man-pages/man2/perf_event_open.2.html. 87 /// 88 /// \param[in] attr 89 /// Configuration information for the event. 90 /// 91 /// \param[in] pid 92 /// The process or thread to be monitored by the event. If \b None, then 93 /// all processes and threads are monitored. 94 /// 95 /// \param[in] cpu 96 /// The cpu to be monitored by the event. If \b None, then all cpus are 97 /// monitored. 98 /// 99 /// \param[in] group_fd 100 /// File descriptor of the group leader. If \b None, then this perf_event 101 /// doesn't belong to a preexisting group. 102 /// 103 /// \param[in] flags 104 /// Bitmask of additional configuration flags. 105 /// 106 /// \return 107 /// If the perf_event_open syscall was successful, a minimal \a PerfEvent 108 /// instance, or an \a llvm::Error otherwise. 109 static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, 110 std::optional<lldb::pid_t> pid, 111 std::optional<lldb::cpu_id_t> cpu, 112 std::optional<long> group_fd, 113 unsigned long flags); 114 115 /// Create a new performance monitoring event via the perf_event_open syscall 116 /// with "default" values for the cpu, group_fd and flags arguments. 117 /// 118 /// Convenience method to be used when the perf event requires minimal 119 /// configuration. It handles the default values of all other arguments. 120 /// 121 /// \param[in] attr 122 /// Configuration information for the event. 123 /// 124 /// \param[in] pid 125 /// The process or thread to be monitored by the event. If \b None, then 126 /// all threads and processes are monitored. 127 static llvm::Expected<PerfEvent> 128 Init(perf_event_attr &attr, std::optional<lldb::pid_t> pid, 129 std::optional<lldb::cpu_id_t> core = std::nullopt); 130 131 /// Mmap the metadata page and the data and aux buffers of the perf event and 132 /// expose them through \a PerfEvent::GetMetadataPage() , \a 133 /// PerfEvent::GetDataBuffer() and \a PerfEvent::GetAuxBuffer(). 134 /// 135 /// This uses mmap underneath, which means that the number of pages mmap'ed 136 /// must be less than the actual data available by the kernel. The metadata 137 /// page is always mmap'ed. 138 /// 139 /// Mmap is needed because the underlying data might be changed by the kernel 140 /// dynamically. 141 /// 142 /// \param[in] num_data_pages 143 /// Number of pages in the data buffer to mmap, must be a power of 2. 144 /// A value of 0 is useful for "dummy" events that only want to access 145 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 146 /// 147 /// \param[in] num_aux_pages 148 /// Number of pages in the aux buffer to mmap, must be a power of 2. 149 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 150 /// buffer. 151 /// 152 /// \param[in] data_buffer_write 153 /// Whether to mmap the data buffer with WRITE permissions. This changes 154 /// the behavior of how the kernel writes to the data buffer. 155 /// 156 /// \return 157 /// \a llvm::Error::success if the mmap operations succeeded, 158 /// or an \a llvm::Error otherwise. 159 llvm::Error MmapMetadataAndBuffers(size_t num_data_pages, 160 size_t num_aux_pages, 161 bool data_buffer_write); 162 163 /// Get the file descriptor associated with the perf event. 164 long GetFd() const; 165 166 /// Get the metadata page from the data section's mmap buffer. 167 /// 168 /// The metadata page is always mmap'ed, even when \a num_data_pages is 0. 169 /// 170 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 171 /// otherwise a failure might happen. 172 /// 173 /// \return 174 /// The data section's \a perf_event_mmap_page. 175 perf_event_mmap_page &GetMetadataPage() const; 176 177 /// Get the data buffer from the data section's mmap buffer. 178 /// 179 /// The data buffer is the region of the data section's mmap buffer where 180 /// perf sample data is located. 181 /// 182 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 183 /// otherwise a failure might happen. 184 /// 185 /// \return 186 /// \a ArrayRef<uint8_t> extending \a data_size bytes from \a data_offset. 187 llvm::ArrayRef<uint8_t> GetDataBuffer() const; 188 189 /// Get the AUX buffer. 190 /// 191 /// AUX buffer is a region for high-bandwidth data streams 192 /// such as IntelPT. This is separate from the metadata and data buffer. 193 /// 194 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 195 /// otherwise a failure might happen. 196 /// 197 /// \return 198 /// \a ArrayRef<uint8_t> extending \a aux_size bytes from \a aux_offset. 199 llvm::ArrayRef<uint8_t> GetAuxBuffer() const; 200 201 /// Read the aux buffer managed by this perf event assuming it was configured 202 /// with PROT_READ permissions only, which indicates that the buffer is 203 /// automatically wrapped and overwritten by the kernel or hardware. To ensure 204 /// that the data is up-to-date and is not corrupted by read-write race 205 /// conditions, the underlying perf_event is paused during read, and later 206 /// it's returned to its initial state. The returned data will be linear, i.e. 207 /// it will fix the circular wrapping the might exist in the buffer. 208 /// 209 /// \return 210 /// A vector with the requested binary data. 211 llvm::Expected<std::vector<uint8_t>> GetReadOnlyAuxBuffer(); 212 213 /// Read the data buffer managed by this perf even assuming it was configured 214 /// with PROT_READ permissions only, which indicates that the buffer is 215 /// automatically wrapped and overwritten by the kernel or hardware. To ensure 216 /// that the data is up-to-date and is not corrupted by read-write race 217 /// conditions, the underlying perf_event is paused during read, and later 218 /// it's returned to its initial state. The returned data will be linear, i.e. 219 /// it will fix the circular wrapping the might exist int he buffer. 220 /// 221 /// \return 222 /// A vector with the requested binary data. 223 llvm::Expected<std::vector<uint8_t>> GetReadOnlyDataBuffer(); 224 225 /// Use the ioctl API to disable the perf event and all the events in its 226 /// group. This doesn't terminate the perf event. 227 /// 228 /// This is no-op if the perf event is already disabled. 229 /// 230 /// \return 231 /// An Error if the perf event couldn't be disabled. 232 llvm::Error DisableWithIoctl(); 233 234 /// Use the ioctl API to enable the perf event and all the events in its 235 /// group. 236 /// 237 /// This is no-op if the perf event is already enabled. 238 /// 239 /// \return 240 /// An Error if the perf event couldn't be enabled. 241 llvm::Error EnableWithIoctl(); 242 243 /// \return 244 /// The size in bytes of the section of the data buffer that has effective 245 /// data. 246 size_t GetEffectiveDataBufferSize() const; 247 248 /// \return 249 /// \b true if and only the perf event is enabled and collecting. 250 bool IsEnabled() const; 251 252 private: 253 /// Create new \a PerfEvent. 254 /// 255 /// \param[in] fd 256 /// File descriptor of the perf event. 257 /// 258 /// \param[in] enabled 259 /// Initial collection state configured for this perf_event. 260 PerfEvent(long fd, bool enabled) 261 : m_fd(new long(fd), resource_handle::FileDescriptorDeleter()), 262 m_enabled(enabled) {} 263 264 /// Wrapper for \a mmap to provide custom error messages. 265 /// 266 /// The parameters are directly forwarded to a \a mmap syscall, 267 /// for information on the parameters visit 268 /// https://man7.org/linux/man-pages/man2/mmap.2.html. 269 /// 270 /// The value of \a GetFd() is passed as the \a fd argument to \a mmap. 271 llvm::Expected<resource_handle::MmapUP> DoMmap(void *addr, size_t length, 272 int prot, int flags, 273 long int offset, 274 llvm::StringRef buffer_name); 275 276 /// Mmap the data buffer of the perf event. 277 /// 278 /// \param[in] num_data_pages 279 /// Number of pages in the data buffer to mmap, must be a power of 2. 280 /// A value of 0 is useful for "dummy" events that only want to access 281 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 282 /// 283 /// \param[in] data_buffer_write 284 /// Whether to mmap the data buffer with WRITE permissions. This changes 285 /// the behavior of how the kernel writes to the data buffer. 286 llvm::Error MmapMetadataAndDataBuffer(size_t num_data_pages, 287 bool data_buffer_write); 288 289 /// Mmap the aux buffer of the perf event. 290 /// 291 /// \param[in] num_aux_pages 292 /// Number of pages in the aux buffer to mmap, must be a power of 2. 293 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 294 /// buffer. 295 llvm::Error MmapAuxBuffer(size_t num_aux_pages); 296 297 /// The file descriptor representing the perf event. 298 resource_handle::FileDescriptorUP m_fd; 299 /// Metadata page and data section where perf samples are stored. 300 resource_handle::MmapUP m_metadata_data_base; 301 /// AUX buffer is a separate region for high-bandwidth data streams 302 /// such as IntelPT. 303 resource_handle::MmapUP m_aux_base; 304 /// The state of the underlying perf_event. 305 bool m_enabled; 306 }; 307 308 /// Create a perf event that tracks context switches on a cpu. 309 /// 310 /// \param[in] cpu_id 311 /// The core to trace. 312 /// 313 /// \param[in] parent_perf_event 314 /// An optional perf event that will be grouped with the 315 /// new perf event. 316 llvm::Expected<PerfEvent> 317 CreateContextSwitchTracePerfEvent(lldb::cpu_id_t cpu_id, 318 const PerfEvent *parent_perf_event = nullptr); 319 320 /// Load \a PerfTscConversionParameters from \a perf_event_mmap_page, if 321 /// available. 322 llvm::Expected<LinuxPerfZeroTscConversion> LoadPerfTscConversionParameters(); 323 324 } // namespace process_linux 325 } // namespace lldb_private 326 327 #endif // LLDB_SOURCE_PLUGINS_PROCESS_LINUX_PERF_H 328