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});