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/lldb-types.h" 19 20 #include "llvm/Support/Error.h" 21 22 #include <chrono> 23 #include <cstdint> 24 #include <linux/perf_event.h> 25 26 namespace lldb_private { 27 namespace process_linux { 28 namespace resource_handle { 29 30 /// Custom deleter for the pointer returned by \a mmap. 31 /// 32 /// This functor type is provided to \a unique_ptr to properly 33 /// unmap the region at destruction time. 34 class MmapDeleter { 35 public: 36 /// Construct new \a MmapDeleter. 37 /// 38 /// \param[in] bytes 39 /// Size of the mmap'ed region in bytes. 40 MmapDeleter(size_t bytes = 0) : m_bytes(bytes) {} 41 42 /// Unmap the mmap'ed region. 43 /// 44 /// If \a m_bytes==0 or \a ptr==nullptr, nothing is unmmapped. 45 /// 46 /// \param[in] ptr 47 /// pointer to the region to be unmmapped. 48 void operator()(void *ptr); 49 50 private: 51 /// Size of the mmap'ed region, in bytes, to be unmapped. 52 size_t m_bytes; 53 }; 54 55 /// Custom deleter for a file descriptor. 56 /// 57 /// This functor type is provided to \a unique_ptr to properly release 58 /// the resources associated with the file descriptor at destruction time. 59 class FileDescriptorDeleter { 60 public: 61 /// Close and free the memory associated with the file descriptor pointer. 62 /// 63 /// Effectively a no-op if \a ptr==nullptr or \a*ptr==-1. 64 /// 65 /// \param[in] ptr 66 /// Pointer to the file descriptor. 67 void operator()(long *ptr); 68 }; 69 70 using FileDescriptorUP = 71 std::unique_ptr<long, resource_handle::FileDescriptorDeleter>; 72 using MmapUP = std::unique_ptr<void, resource_handle::MmapDeleter>; 73 74 } // namespace resource_handle 75 76 /// Thin wrapper of the perf_event_open API. 77 /// 78 /// Exposes the metadata page and data and aux buffers of a perf event. 79 /// Handles the management of the event's file descriptor and mmap'ed 80 /// regions. 81 class PerfEvent { 82 public: 83 /// Create a new performance monitoring event via the perf_event_open syscall. 84 /// 85 /// The parameters are directly forwarded to a perf_event_open syscall, 86 /// for additional information on the parameters visit 87 /// https://man7.org/linux/man-pages/man2/perf_event_open.2.html. 88 /// 89 /// \param[in] attr 90 /// Configuration information for the event. 91 /// 92 /// \param[in] pid 93 /// The process to be monitored by the event. 94 /// 95 /// \param[in] cpu 96 /// The cpu to be monitored by the event. 97 /// 98 /// \param[in] group_fd 99 /// File descriptor of the group leader. 100 /// 101 /// \param[in] flags 102 /// Bitmask of additional configuration flags. 103 /// 104 /// \return 105 /// If the perf_event_open syscall was successful, a minimal \a PerfEvent 106 /// instance, or an \a llvm::Error otherwise. 107 static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, lldb::pid_t pid, 108 int cpu, int group_fd, 109 unsigned long flags); 110 111 /// Create a new performance monitoring event via the perf_event_open syscall 112 /// with "default" values for the cpu, group_fd and flags arguments. 113 /// 114 /// Convenience method to be used when the perf event requires minimal 115 /// configuration. It handles the default values of all other arguments. 116 /// 117 /// \param[in] attr 118 /// Configuration information for the event. 119 /// 120 /// \param[in] pid 121 /// The process to be monitored by the event. 122 static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, lldb::pid_t pid); 123 124 /// Mmap the metadata page and the data and aux buffers of the perf event and 125 /// expose them through \a PerfEvent::GetMetadataPage() , \a 126 /// PerfEvent::GetDataBuffer() and \a PerfEvent::GetAuxBuffer(). 127 /// 128 /// This uses mmap underneath, which means that the number of pages mmap'ed 129 /// must be less than the actual data available by the kernel. The metadata 130 /// page is always mmap'ed. 131 /// 132 /// Mmap is needed because the underlying data might be changed by the kernel 133 /// dynamically. 134 /// 135 /// \param[in] num_data_pages 136 /// Number of pages in the data buffer to mmap, must be a power of 2. 137 /// A value of 0 is useful for "dummy" events that only want to access 138 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 139 /// 140 /// \param[in] num_aux_pages 141 /// Number of pages in the aux buffer to mmap, must be a power of 2. 142 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 143 /// buffer. 144 /// 145 /// \return 146 /// \a llvm::Error::success if the mmap operations succeeded, 147 /// or an \a llvm::Error otherwise. 148 llvm::Error MmapMetadataAndBuffers(size_t num_data_pages, 149 size_t num_aux_pages); 150 151 /// Get the file descriptor associated with the perf event. 152 long GetFd() const; 153 154 /// Get the metadata page from the data section's mmap buffer. 155 /// 156 /// The metadata page is always mmap'ed, even when \a num_data_pages is 0. 157 /// 158 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 159 /// otherwise a failure might happen. 160 /// 161 /// \return 162 /// The data section's \a perf_event_mmap_page. 163 perf_event_mmap_page &GetMetadataPage() const; 164 165 /// Get the data buffer from the data section's mmap buffer. 166 /// 167 /// The data buffer is the region of the data section's mmap buffer where 168 /// perf sample data is located. 169 /// 170 /// This should be called only after \a PerfEvent::MmapMetadataAndBuffers, 171 /// otherwise a failure might happen. 172 /// 173 /// \return 174 /// \a ArrayRef<uint8_t> extending \a data_size bytes from \a data_offset. 175 llvm::ArrayRef<uint8_t> GetDataBuffer() const; 176 177 /// Get the AUX buffer. 178 /// 179 /// AUX buffer is a region for high-bandwidth data streams 180 /// such as IntelPT. This is separate from the metadata and data buffer. 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 aux_size bytes from \a aux_offset. 187 llvm::ArrayRef<uint8_t> GetAuxBuffer() const; 188 189 private: 190 /// Create new \a PerfEvent. 191 /// 192 /// \param[in] fd 193 /// File descriptor of the perf event. 194 PerfEvent(long fd) 195 : m_fd(new long(fd), resource_handle::FileDescriptorDeleter()), 196 m_metadata_data_base(), m_aux_base() {} 197 198 /// Wrapper for \a mmap to provide custom error messages. 199 /// 200 /// The parameters are directly forwarded to a \a mmap syscall, 201 /// for information on the parameters visit 202 /// https://man7.org/linux/man-pages/man2/mmap.2.html. 203 /// 204 /// The value of \a GetFd() is passed as the \a fd argument to \a mmap. 205 llvm::Expected<resource_handle::MmapUP> DoMmap(void *addr, size_t length, 206 int prot, int flags, 207 long int offset, 208 llvm::StringRef buffer_name); 209 210 /// Mmap the data buffer of the perf event. 211 /// 212 /// \param[in] num_data_pages 213 /// Number of pages in the data buffer to mmap, must be a power of 2. 214 /// A value of 0 is useful for "dummy" events that only want to access 215 /// the metadata, \a perf_event_mmap_page, or the aux buffer. 216 llvm::Error MmapMetadataAndDataBuffer(size_t num_data_pages); 217 218 /// Mmap the aux buffer of the perf event. 219 /// 220 /// \param[in] num_aux_pages 221 /// Number of pages in the aux buffer to mmap, must be a power of 2. 222 /// A value of 0 effectively is a no-op and no data is mmap'ed for this 223 /// buffer. 224 llvm::Error MmapAuxBuffer(size_t num_aux_pages); 225 226 /// The file descriptor representing the perf event. 227 resource_handle::FileDescriptorUP m_fd; 228 /// Metadata page and data section where perf samples are stored. 229 resource_handle::MmapUP m_metadata_data_base; 230 /// AUX buffer is a separate region for high-bandwidth data streams 231 /// such as IntelPT. 232 resource_handle::MmapUP m_aux_base; 233 }; 234 235 /// TSC to nanoseconds conversion values defined by the Linux perf_event API 236 /// when the capibilities cap_user_time and cap_user_time_zero are set. See the 237 /// documentation of `time_zero` in 238 /// https://man7.org/linux/man-pages/man2/perf_event_open.2.html for more 239 /// information. 240 struct PerfTscConversionParameters { 241 uint32_t m_time_mult; 242 uint16_t m_time_shift; 243 uint64_t m_time_zero; 244 245 /// Convert TSC value to nanosecond wall time. 246 /// 247 /// \a param[in] tsc 248 /// The TSC value to be converted. 249 /// 250 /// \return 251 /// Nanosecond wall time. 252 std::chrono::nanoseconds ToWallTime(uint64_t tsc); 253 }; 254 255 /// Fetch \a PerfTscConversionParameters from \a perf_event_mmap_page, if 256 /// available. 257 llvm::Expected<PerfTscConversionParameters> FetchPerfTscConversionParameters(); 258 259 } // namespace process_linux 260 } // namespace lldb_private 261 262 #endif // LLDB_SOURCE_PLUGINS_PROCESS_LINUX_PERF_H 263