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 to be monitored by the event. 113 /// 114 /// \param[in] cpu 115 /// The cpu to be monitored by the event. 116 /// 117 /// \param[in] group_fd 118 /// File descriptor of the group leader. 119 /// 120 /// \param[in] flags 121 /// Bitmask of additional configuration flags. 122 /// 123 /// \return 124 /// If the perf_event_open syscall was successful, a minimal \a PerfEvent 125 /// instance, or an \a llvm::Error otherwise. 126 static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, lldb::pid_t pid, 127 int cpu, int group_fd, 128 unsigned long flags); 129 130 /// Create a new performance monitoring event via the perf_event_open syscall 131 /// with "default" values for the cpu, group_fd and flags arguments. 132 /// 133 /// Convenience method to be used when the perf event requires minimal 134 /// configuration. It handles the default values of all other arguments. 135 /// 136 /// \param[in] attr 137 /// Configuration information for the event. 138 /// 139 /// \param[in] pid 140 /// The process to be monitored by the event. 141 static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, lldb::pid_t pid); 142 143 /// Mmap the metadata page and the data and aux buffers of the perf event and 144 /// expose them through \a PerfEvent::GetMetadataPage() , \a 145 /// PerfEvent::GetDataBuffer() and \a PerfEvent::GetAuxBuffer(). 146 /// 147 /// This uses mmap underneath, which means that the number of pages mmap'ed 148 /// must be less than the actual data available by the kernel. The metadata 149 /// page is always mmap'ed. 150 /// 151 /// Mmap is needed because the underlying data might be changed by the kernel 152 /// dynamically. 153 /// 154 /// \param[in] num_data_pages 155 /// Number of pages in the data buffer to mmap, must be a power of 2. 156 /// A value of 0 is useful for "dummy" events that only want to access 157 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 158 /// 159 /// \param[in] num_aux_pages 160 /// Number of pages in the aux buffer to mmap, must be a power of 2. 161 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 162 /// buffer. 163 /// 164 /// \return 165 /// \a llvm::Error::success if the mmap operations succeeded, 166 /// or an \a llvm::Error otherwise. 167 llvm::Error MmapMetadataAndBuffers(size_t num_data_pages, 168 size_t num_aux_pages); 169 170 /// Get the file descriptor associated with the perf event. 171 long GetFd() const; 172 173 /// Get the metadata page from the data section's mmap buffer. 174 /// 175 /// The metadata page is always mmap'ed, even when \a num_data_pages is 0. 176 /// 177 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 178 /// otherwise a failure might happen. 179 /// 180 /// \return 181 /// The data section's \a perf_event_mmap_page. 182 perf_event_mmap_page &GetMetadataPage() const; 183 184 /// Get the data buffer from the data section's mmap buffer. 185 /// 186 /// The data buffer is the region of the data section's mmap buffer where 187 /// perf sample data is located. 188 /// 189 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 190 /// otherwise a failure might happen. 191 /// 192 /// \return 193 /// \a ArrayRef<uint8_t> extending \a data_size bytes from \a data_offset. 194 llvm::ArrayRef<uint8_t> GetDataBuffer() const; 195 196 /// Get the AUX buffer. 197 /// 198 /// AUX buffer is a region for high-bandwidth data streams 199 /// such as IntelPT. This is separate from the metadata and data buffer. 200 /// 201 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 202 /// otherwise a failure might happen. 203 /// 204 /// \return 205 /// \a ArrayRef<uint8_t> extending \a aux_size bytes from \a aux_offset. 206 llvm::ArrayRef<uint8_t> GetAuxBuffer() const; 207 208 private: 209 /// Create new \a PerfEvent. 210 /// 211 /// \param[in] fd 212 /// File descriptor of the perf event. 213 PerfEvent(long fd) 214 : m_fd(new long(fd), resource_handle::FileDescriptorDeleter()), 215 m_metadata_data_base(), m_aux_base() {} 216 217 /// Wrapper for \a mmap to provide custom error messages. 218 /// 219 /// The parameters are directly forwarded to a \a mmap syscall, 220 /// for information on the parameters visit 221 /// https://man7.org/linux/man-pages/man2/mmap.2.html. 222 /// 223 /// The value of \a GetFd() is passed as the \a fd argument to \a mmap. 224 llvm::Expected<resource_handle::MmapUP> DoMmap(void *addr, size_t length, 225 int prot, int flags, 226 long int offset, 227 llvm::StringRef buffer_name); 228 229 /// Mmap the data buffer of the perf event. 230 /// 231 /// \param[in] num_data_pages 232 /// Number of pages in the data buffer to mmap, must be a power of 2. 233 /// A value of 0 is useful for "dummy" events that only want to access 234 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 235 llvm::Error MmapMetadataAndDataBuffer(size_t num_data_pages); 236 237 /// Mmap the aux buffer of the perf event. 238 /// 239 /// \param[in] num_aux_pages 240 /// Number of pages in the aux buffer to mmap, must be a power of 2. 241 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 242 /// buffer. 243 llvm::Error MmapAuxBuffer(size_t num_aux_pages); 244 245 /// The file descriptor representing the perf event. 246 resource_handle::FileDescriptorUP m_fd; 247 /// Metadata page and data section where perf samples are stored. 248 resource_handle::MmapUP m_metadata_data_base; 249 /// AUX buffer is a separate region for high-bandwidth data streams 250 /// such as IntelPT. 251 resource_handle::MmapUP m_aux_base; 252 }; 253 254 /// Load \a PerfTscConversionParameters from \a perf_event_mmap_page, if 255 /// available. 256 llvm::Expected<LinuxPerfZeroTscConversion> LoadPerfTscConversionParameters(); 257 258 } // namespace process_linux 259 } // namespace lldb_private 260 261 #endif // LLDB_SOURCE_PLUGINS_PROCESS_LINUX_PERF_H 262