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