perf_event/events/tracepoint.rs
1use std::num::ParseIntError;
2use std::path::{Path, PathBuf};
3use std::{fmt, io};
4
5use perf_event_open_sys::bindings;
6
7use crate::events::Event;
8
9/// Kernel tracepoint event.
10///
11/// Tracepoints allow you to dynamically insert breakpoints into specific hook
12/// points defined by the kernel. These can be used to count function executions
13/// or to attach eBPF programs that run during those breakpoints.
14///
15/// Tracepoints are similar to kprobes. The difference, however, is that
16/// tracepoints are stable and documented. On the other hand, kprobes can be
17/// inserted (almost) anywhere within the kernel whereas tracepoints are
18/// restricted to only the locations at which they have been defined.
19///
20/// Note that it is possible to create tracepoints from kprobes by using
21/// [`perf probe`].
22///
23/// [`perf probe`]: https://man7.org/linux/man-pages/man1/perf-probe.1.html
24#[derive(Clone, Copy, Debug)]
25pub struct Tracepoint {
26 id: u64,
27}
28
29impl Tracepoint {
30 /// Create a tracepoint directly from its raw ID.
31 ///
32 /// Usually you will have to look within debugfs to get this ID.
33 /// [`with_name`](Tracepoint::with_name) is a helper to do this by looking
34 /// up the event ID in the debugfs instance mounted at `/sys/kernel/debug`.
35 pub fn with_id(id: u64) -> Self {
36 Self { id }
37 }
38
39 /// Create a tracepoint by looking up its ID within `/sys/kernel/debug`.
40 ///
41 /// Event names are listed under `/sys/kernel/debug/tracing/events`. All
42 /// this method does is read the file at
43 /// `/sys/kernel/debug/tracing/events/<name>/id` and use the contents of the
44 /// `id` file as the tracepoint id.
45 ///
46 /// Note that `/sys/kernel/debug` is only accessible if running as root or
47 /// if the process has `CAP_SYS_ADMIN`.
48 ///
49 /// # Example
50 /// Create a tracepoint event for the `sched_switch` tracepoint.
51 /// ```
52 /// # use perf_event::events::Tracepoint;
53 /// # fn run() -> std::io::Result<()> {
54 /// let tracepoint = Tracepoint::with_name("sched/sched_switch")?;
55 /// # Ok(())
56 /// # }
57 /// # let _ = run();
58 /// ```
59 pub fn with_name(name: impl AsRef<Path>) -> io::Result<Self> {
60 let mut path = PathBuf::from("/sys/kernel/debug/tracing/events");
61 path.push(name.as_ref());
62 path.push("id");
63
64 let id = std::fs::read_to_string(&path)?
65 .trim_end()
66 .parse()
67 .map_err(move |e| {
68 io::Error::new(io::ErrorKind::Other, UnparseableIdFile::new(path, e))
69 })?;
70
71 Ok(Self::with_id(id))
72 }
73
74 /// Get the id of this tracepoint.
75 pub fn id(&self) -> u64 {
76 self.id
77 }
78}
79
80impl Event for Tracepoint {
81 fn update_attrs(self, attr: &mut bindings::perf_event_attr) {
82 attr.type_ = bindings::PERF_TYPE_TRACEPOINT;
83 attr.config = self.id;
84 }
85}
86
87#[derive(Debug)]
88struct UnparseableIdFile {
89 path: PathBuf,
90 source: ParseIntError,
91}
92
93impl UnparseableIdFile {
94 fn new(path: PathBuf, source: ParseIntError) -> Self {
95 Self { path, source }
96 }
97}
98
99impl fmt::Display for UnparseableIdFile {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 f.write_fmt(format_args!(
102 "unparseable tracepoint id file `{}`",
103 self.path.display()
104 ))
105 }
106}
107
108impl std::error::Error for UnparseableIdFile {
109 fn cause(&self) -> Option<&dyn std::error::Error> {
110 Some(&self.source)
111 }
112}