perf_event_open/config/
target.rs

1use std::fs::File;
2use std::os::fd::AsRawFd;
3
4use crate::ffi::bindings as b;
5
6/// Monitor all processes (if [`Proc`] is not set) or all CPUs (if [`Cpu`] is not set).
7#[derive(Clone, Copy, Debug)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct All;
10
11/// Which CPU to monitor.
12#[derive(Clone, Copy, Debug)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct Cpu(pub u32);
15
16impl Cpu {
17    /// Monitor all CPUs.
18    ///
19    /// This is an alias for [`All`].
20    pub const ALL: All = All;
21}
22
23/// Which process (thread) to monitor.
24///
25/// Construct with pid or tid.
26///
27/// `Proc(0)` indicates the current process.
28#[derive(Clone, Copy, Debug)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30pub struct Proc(pub u32);
31
32impl Proc {
33    /// Monitor all processes.
34    ///
35    /// This is an alias for [`All`].
36    pub const ALL: All = All;
37
38    /// Monitor current process.
39    pub const CURRENT: Proc = Proc(0);
40}
41
42/// Which cgroup to monitor.
43///
44/// For instance, if the cgroup to monitor is called test, then a file descriptor opened on
45/// `/dev/cgroup/test` (assuming cgroupfs is mounted on `/dev/cgroup`) should be passed.
46///
47/// cgroup monitoring is available only for system-wide events and may therefore require
48/// extra permissions.
49#[derive(Clone, Copy, Debug)]
50pub struct Cgroup<'a>(pub &'a File);
51
52/// Event target, the process (or cgroup) and CPU to monitor.
53///
54/// To create an event target, combine these types in a tuple: [`Proc`] (or [`Cgroup`]), [`Cpu`] and [`All`].
55///
56/// For example, we want to monitor process with pid 12345 on all CPUs: `(Pid(12345), Cpu::ALL)`.
57/// The order of types in the tuples is not senstive because we impl `Into<Target>` for these
58/// swapped tuples, e.g. `(Cpu::ALL, Pid(12345))` has the same semantics as the example above.
59///
60/// This design limits what we can monitor at compile time. For example, the kernel not support
61/// monitoring any process on all CPUs, or a cgroup on all CPUs.
62#[derive(Clone)]
63pub struct Target {
64    pub(crate) pid: i32,
65    pub(crate) cpu: i32,
66    pub(crate) flags: u64,
67}
68
69macro_rules! into_target {
70    ($ty: ty, $destruct: tt, $pid: expr, $cpu: expr, $flags: expr) => {
71        impl From<$ty> for Target {
72            fn from($destruct: $ty) -> Self {
73                Target {
74                    pid: $pid as _,
75                    cpu: $cpu as _,
76                    flags: $flags as _,
77                }
78            }
79        }
80    };
81}
82
83into_target!((Proc, Cpu), (Proc(pid), Cpu(cpu)), pid, cpu, 0);
84into_target!((Cpu, Proc), (Cpu(cpu), Proc(pid)), pid, cpu, 0);
85
86into_target!((Proc, All), (Proc(pid), _), pid, -1, 0);
87into_target!((All, Proc), (_, Proc(pid)), pid, -1, 0);
88
89into_target!((Cpu, All), (Cpu(cpu), _), -1, cpu, 0);
90into_target!((All, Cpu), (_, Cpu(cpu)), -1, cpu, 0);
91
92into_target!(
93    (Cgroup<'_>, Cpu),
94    (Cgroup(file), Cpu(cpu)),
95    file.as_raw_fd(),
96    cpu,
97    b::PERF_FLAG_PID_CGROUP
98);
99into_target!(
100    (Cpu, Cgroup<'_>),
101    (Cpu(cpu), Cgroup(file)),
102    file.as_raw_fd(),
103    cpu,
104    b::PERF_FLAG_PID_CGROUP
105);
106
107// For why `(CgroupFd, Any)` is invalid:
108// https://github.com/torvalds/linux/blob/4dc1d1bec89864d8076e5ab314f86f46442bfb02/kernel/events/core.c#L12835