perf_event_open/sample/record/
task.rs

1use super::{RecordId, SampleType, Task};
2use crate::ffi::deref_offset;
3
4/// Process exited.
5///
6/// Please check module-level docs for examples.
7///
8/// # Examples
9///
10/// ```rust
11/// use std::sync::atomic::{AtomicBool, Ordering};
12/// use std::sync::mpsc::channel;
13/// use std::thread;
14///
15/// use perf_event_open::config::{Cpu, Opts, Proc};
16/// use perf_event_open::count::Counter;
17/// use perf_event_open::event::sw::Software;
18/// # use perf_event_open::sample::record::Record;
19///
20/// static WAIT: AtomicBool = AtomicBool::new(true);
21///
22/// let (tid_tx, tid_rx) = channel();
23/// let handle = thread::spawn(move || {
24///     tid_tx.send(unsafe { libc::gettid() }).unwrap();
25///     while WAIT.load(Ordering::Relaxed) {
26///         std::hint::spin_loop();
27///     }
28///     thread::spawn(|| {}); // Fork here.
29/// });
30///
31/// let event = Software::Dummy;
32/// let target = (Proc(tid_rx.recv().unwrap() as _), Cpu::ALL);
33///
34/// let mut opts = Opts::default();
35/// opts.extra_record.task = true;
36///
37/// let counter = Counter::new(event, target, opts).unwrap();
38/// let sampler = counter.sampler(5).unwrap();
39///
40/// counter.enable().unwrap();
41/// WAIT.store(false, Ordering::Relaxed);
42/// handle.join().unwrap(); // Exit here.
43///
44/// # let mut vec = vec![];
45/// for it in sampler.iter() {
46///     println!("{:-?}", it);
47///     # vec.push(it);
48/// }
49/// # assert!(vec.iter().any(|(_, it)| matches!(it, Record::Fork(_))));
50/// # assert!(vec.iter().any(|(_, it)| matches!(it, Record::Exit(_))));
51/// ```
52///
53/// See also [`ExtraRecords::task`][crate::config::ExtraRecord::task].
54#[derive(Clone)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56pub struct Exit {
57    /// Record IDs.
58    pub record_id: Option<RecordId>,
59
60    /// Task info.
61    pub task: Task,
62    /// Parent task info.
63    pub parent_task: Task,
64    /// Timestamp.
65    pub time: u64,
66}
67
68impl Exit {
69    pub(crate) unsafe fn from_ptr(mut ptr: *const u8, sample_id_all: Option<SampleType>) -> Self {
70        // https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L912
71        // struct {
72        //     struct perf_event_header header;
73        //     u32 pid, ppid;
74        //     u32 tid, ptid;
75        //     u64 time;
76        //     struct sample_id sample_id;
77        // };
78
79        let pid = deref_offset(&mut ptr);
80        let ppid = deref_offset(&mut ptr);
81        let tid = deref_offset(&mut ptr);
82        let ptid = deref_offset(&mut ptr);
83
84        // https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L8428
85        let time = deref_offset(&mut ptr);
86        let record_id = sample_id_all.map(|SampleType(ty)| RecordId::from_ptr(ptr, ty));
87
88        let task = Task { pid, tid };
89        let parent_task = Task {
90            pid: ppid,
91            tid: ptid,
92        };
93
94        Self {
95            record_id,
96            task,
97            parent_task,
98            time,
99        }
100    }
101}
102
103super::from!(Exit);
104
105super::debug!(Exit {
106    {record_id?},
107    {task},
108    {parent_task},
109    {time},
110});
111
112/// Process forked.
113///
114/// See [`Exit`] for examples.
115///
116/// See also [`ExtraRecords::task`][crate::config::ExtraRecord::task].
117#[derive(Clone)]
118#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
119pub struct Fork {
120    /// Record IDs.
121    pub record_id: Option<RecordId>,
122
123    /// Task info.
124    pub task: Task,
125    /// Parent task info.
126    pub parent_task: Task,
127    /// Timestamp.
128    pub time: u64,
129}
130
131impl Fork {
132    pub(crate) unsafe fn from_ptr(ptr: *const u8, sample_id_all: Option<SampleType>) -> Self {
133        // https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L8423
134        let layout = Exit::from_ptr(ptr, sample_id_all);
135
136        Self {
137            record_id: layout.record_id,
138            task: layout.task,
139            parent_task: layout.parent_task,
140            time: layout.time,
141        }
142    }
143}
144
145super::from!(Fork);
146
147super::debug!(Fork {
148    {record_id?},
149    {task},
150    {parent_task},
151    {time},
152});