perf_event_open_sys/
lib.rs

1//! Direct, unsafe bindings for Linux [`perf_event_open`][man] and friends.
2//!
3//! Linux's `perf_event_open` system call provides access to the processor's
4//! performance measurement counters (things like instructions retired, cache
5//! misses, and so on), kernel counters (context switches, page faults), and
6//! many other sources of performance information.
7//!
8//! You can't get the `perf_event_open` function from the `libc` crate, as you
9//! would any other system call. The Linux standard C library does not provide a
10//! binding for this function or its associated types and constants.
11//!
12//! Rust analogs to the C types and constants from `<linux/perf_event.h>` and
13//! `<linux/hw_breakpoint.h>`, generated with `bindgen`, are available in the
14//! [`bindings`] module.
15//!
16//! There are several ioctls for use with `perf_event_open` file descriptors;
17//! see the [`ioctls`] module for those.
18//!
19//! For a safe and convenient interface to this functionality, see the
20//! [`perf_event`] crate.
21//!
22//! ## Using the raw API
23//!
24//! As the kernel interface evolves, the struct and union types from the
25//! [`bindings`] module may acquire new fields. To ensure that your code will
26//! continue to compile against newer versions of this crate, you should
27//! construct values of these types by calling their `Default` implementations,
28//! which return zero-filled values, and then assigning to the fields you care
29//! about. For example:
30//!
31//! ```
32//! use perf_event_open_sys as sys;
33//!
34//! // Construct a zero-filled `perf_event_attr`.
35//! let mut attrs = sys::bindings::perf_event_attr::default();
36//!
37//! // Populate the fields we need.
38//! attrs.size = std::mem::size_of::<sys::bindings::perf_event_attr>() as u32;
39//! attrs.type_ = sys::bindings::PERF_TYPE_HARDWARE;
40//! attrs.config = sys::bindings::PERF_COUNT_HW_INSTRUCTIONS as u64;
41//! attrs.set_disabled(1);
42//! attrs.set_exclude_kernel(1);
43//! attrs.set_exclude_hv(1);
44//!
45//! // Make the system call.
46//! let result = unsafe {
47//!     sys::perf_event_open(&mut attrs, 0, -1, -1, 0)
48//! };
49//!
50//! if result < 0 {
51//!     // ... handle error
52//! }
53//!
54//! // ... use `result` as a raw file descriptor
55//! ```
56//!
57//! It is not necessary to adjust `size` to what the running kernel expects:
58//! older kernels can accept newer `perf_event_attr` structs, and vice versa. As
59//! long as the `size` field was properly initialized, an error result of
60//! `E2BIG` indicates that the `attrs` structure has requested behavior the
61//! kernel is too old to support.
62//!
63//! When `E2BIG` is returned, the kernel writes the size it expected back to the
64//! `size` field of the `attrs` struct. Again, if you want to retry the call, it
65//! is not necessary to adjust the size you pass to match what the kernel passed
66//! back. The size from the kernel just indicates which version of the API the
67//! kernel supports; see the documentation for the `PERF_EVENT_ATTR_SIZE_VER...`
68//! constants for details.
69//!
70//! ## Kernel versions
71//!
72//! The bindings in this crate are generated from the Linux kernel headers
73//! packaged by Fedora as:
74//! - x86_64: `kernel-headers-6.13.3-200.fc41.x86_64` (`PERF_ATTR_SIZE_VER8`)
75//! - aarch64: `kernel-headers-5.18.4-201.fc36.aarch64` (`PERF_ATTR_SIZE_VER7`)
76//!
77//! RISC-V binding is generated from the Linux kernel headers pacakged by Arch Linux:
78//!
79//! - riscv64: linux-headers 6.0.9.arch1-1 riscv64
80//!
81//! As explained above, bugs aside, it is not necessary to use the version of
82//! these structures that matches the kernel you want to run under, so it should
83//! always be acceptable to use the latest version of this crate, even if you
84//! want to support older kernels.
85//!
86//! This crate's `README.md` file includes instructions on regenerating the
87//! bindings from newer kernel headers. However, this can be a breaking change
88//! for users that have not followed the advice above, so regeneration should
89//! cause a major version increment.
90//!
91//! If you need features that are available only in a more recent version of the
92//! types than this crate provides, please file an issue.
93//!
94//! ## Linux API Backward/Forward Compatibility Strategy
95//!
96//! (This is more detail than necessary if you just want to use the crate. I
97//! want to write this down somewhere so that I have something to refer to when
98//! I forget the details.)
99//!
100//! It is an important principle of Linux kernel development that new versions
101//! of the kernel should not break userspace. If upgrading your kernel breaks a
102//! user program, then that's a bug in the kernel. (This refers to the run-time
103//! interface. I don't know what the stability rules are for the kernel headers:
104//! can new headers cause old code to fail to compile? Anyway, run time is our
105//! concern here.)
106//!
107//! But when you have an open-ended, complex system call like `perf_event_open`,
108//! it's really important for the interface to be able to evolve. Certainly, old
109//! programs must run properly on new kernels, but ideally, it should work the
110//! other way, too: a program built against a newer version of the kernel
111//! headers should run on an older kernel, as long as it only requests features
112//! the old kernel actually supports. That is, simply compiling against newer
113//! headers should not be disqualifying - only using those new headers to
114//! request new features the running kernel can't provide should cause an error.
115//!
116//! Consider the specific case of passing a struct like `perf_event_attr` to a
117//! system call like `perf_event_open`. In general, there are two versions of
118//! the struct in play: the version the user program was compiled against, and
119//! the version the running kernel was compiled against. How can we let old
120//! programs call `perf_event_open` on new kernels, and vice versa?
121//!
122//! Linux has a neat strategy for making this work. There are four rules:
123//!
124//! -   Every system call that passes a struct to the kernel includes some
125//!     indication of how large userspace thinks that struct is. For
126//!     `perf_event_open`, it's the `size` field of the `perf_event_attr`
127//!     struct. For `ioctl`s that pass a struct, it's a bitfield of the
128//!     `request` value.
129//!
130//! -   Fields are never deleted from structs. At most, newer kernel headers may
131//!     rename them to `__reserved_foo` or something like that, but once a field
132//!     has been placed, its layout in the struct never changes.
133//!
134//! -   New fields are added to the end of structs.
135//!
136//! -   New fields' semantics are chosen such that filling them with zeros
137//!     preserves the old behavior. That is, turning an old struct into a new
138//!     struct by extending it with zero bytes should always give you a new
139//!     struct with the same meaning as the old struct.
140//!
141//! Then, the kernel's strategy for receiving structs from userspace is as
142//! follows (according to the comments for `copy_struct_from_user` in
143//! the kernel source `include/linux/uaccess.h`):
144//!
145//! -   If the kernel's struct is larger than the one passed from userspace,
146//!     then that means the kernel is newer than the userspace program. The
147//!     kernel copies the userspace data into the initial bytes of its own
148//!     struct, and zeros the remaining bytes. Since zeroed fields have no
149//!     effect, the resulting struct properly reflects the user's intent.
150//!
151//! -   If the kernel's struct is smaller than the one passed from userspace,
152//!     then that means that a userspace program compiled against newer kernel
153//!     headers is running on an older kernel. The kernel checks that the excess
154//!     bytes in the userspace struct are all zero; if they are not, the system
155//!     call returns `E2BIG`, indicating that userspace has requested a feature
156//!     the kernel doesn't support. If they are all zero, then the kernel
157//!     initializes its own struct with the bytes from the start of the
158//!     userspace struct, and drops the rest. Since the dropped bytes were all
159//!     zero, they did not affect the requested behavior, and the resulting
160//!     struct reflects the user's intent.
161//!
162//! -   In either case, the kernel verifies that any `__reserved_foo` fields in
163//!     its own version of the struct are zero.
164//!
165//! This covers both the old-on-new and new-on-old cases, and returns an error
166//! only when the call requests functionality the kernel doesn't support.
167//!
168//! You can find one example of using `perf_event_open` in the [`perf_event`]
169//! crate, which provides a safe interface to a subset of `perf_event_open`'s
170//! functionality.
171//!
172//! ## Using perf types on other platforms
173//!
174//! Although the functions in this crate are only available on Linux
175//! and Android, the crate itself should build on Windows and Mac as
176//! well. On those platforms, only the `bindings` module is available:
177//! the types are useful to code that needs to parse perf data
178//! produced on Linux.
179//!
180//! [`bindings`]: bindings/index.html
181//! [`ioctls`]: ioctls/index.html
182//! [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
183//! [`perf_event`]: https://crates.io/crates/perf_event
184
185#[cfg(target_arch = "aarch64")]
186#[path = "bindings_aarch64.rs"]
187pub mod bindings;
188
189#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
190#[path = "bindings_x86_64.rs"]
191pub mod bindings;
192
193#[cfg(any(target_arch = "riscv64"))]
194#[path = "bindings_riscv64.rs"]
195pub mod bindings;
196
197// Provide actual callable code only on Linux/Android. See "Using perf
198// types on other platforms", in the top-level crate docs.
199#[cfg(any(target_os = "linux", target_os = "android"))]
200mod functions;
201
202#[cfg(any(target_os = "linux", target_os = "android"))]
203pub use functions::*;