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