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