Skip to content

Commit bb6640e

Browse files
committed
Remove Builder::group and replace it with Group::add
Builder::group means that the builder now has store a mutable reference to a group. This affects the interface of a Builder (e.g. it can no longer be cloned). A different approach, although not necessarily better, is to add counters to a group. This change makes it so that adding counters to a group now involves calling Group::add with the Builder instance.
1 parent 7d9a59c commit bb6640e

File tree

7 files changed

+95
-116
lines changed

7 files changed

+95
-116
lines changed

perf-event/examples/big-group.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,12 @@ fn main() -> std::io::Result<()> {
1313
};
1414

1515
let mut group = Group::new()?;
16-
let access_counter = Builder::new(ACCESS).group(&mut group).build()?;
17-
let miss_counter = Builder::new(MISS).group(&mut group).build()?;
18-
let branches = Builder::new(Hardware::BRANCH_INSTRUCTIONS)
19-
.group(&mut group)
20-
.build()?;
21-
let missed_branches = Builder::new(Hardware::BRANCH_MISSES)
22-
.group(&mut group)
23-
.build()?;
24-
let insns = Builder::new(Hardware::INSTRUCTIONS)
25-
.group(&mut group)
26-
.build()?;
27-
let cycles = Builder::new(Hardware::CPU_CYCLES)
28-
.group(&mut group)
29-
.build()?;
16+
let access_counter = group.add(&Builder::new(ACCESS))?;
17+
let miss_counter = group.add(&Builder::new(MISS))?;
18+
let branches = group.add(&Builder::new(Hardware::BRANCH_INSTRUCTIONS))?;
19+
let missed_branches = group.add(&Builder::new(Hardware::BRANCH_MISSES))?;
20+
let insns = group.add(&Builder::new(Hardware::INSTRUCTIONS))?;
21+
let cycles = group.add(&Builder::new(Hardware::CPU_CYCLES))?;
3022

3123
// Note that if you add more counters than you actually have hardware for,
3224
// the kernel will time-slice them, which means you may get no coverage for

perf-event/examples/group.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,10 @@ fn main() -> std::io::Result<()> {
1313
};
1414

1515
let mut group = Group::new()?;
16-
let access_counter = Builder::new(ACCESS).group(&mut group).build()?;
17-
let miss_counter = Builder::new(MISS).group(&mut group).build()?;
18-
let branches = Builder::new(Hardware::BRANCH_INSTRUCTIONS)
19-
.group(&mut group)
20-
.build()?;
21-
let missed_branches = Builder::new(Hardware::BRANCH_MISSES)
22-
.group(&mut group)
23-
.build()?;
16+
let access_counter = group.add(&Builder::new(ACCESS))?;
17+
let miss_counter = group.add(&Builder::new(MISS))?;
18+
let branches = group.add(&Builder::new(Hardware::BRANCH_INSTRUCTIONS))?;
19+
let missed_branches = group.add(&Builder::new(Hardware::BRANCH_MISSES))?;
2420

2521
// Note that if you add more counters than you actually have hardware for,
2622
// the kernel will time-slice them, which means you may get no coverage for

perf-event/examples/println-cpi.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,8 @@ fn main() -> std::io::Result<()> {
33
use perf_event::{Builder, Group};
44

55
let mut group = Group::new()?;
6-
let cycles = Builder::new(Hardware::CPU_CYCLES)
7-
.group(&mut group)
8-
.build()?;
9-
let insns = Builder::new(Hardware::INSTRUCTIONS)
10-
.group(&mut group)
11-
.build()?;
6+
let cycles = group.add(&Builder::new(Hardware::CPU_CYCLES))?;
7+
let insns = group.add(&Builder::new(Hardware::INSTRUCTIONS))?;
128

139
let vec = (0..=51).collect::<Vec<_>>();
1410

perf-event/src/builder.rs

Lines changed: 35 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::fs::File;
22
use std::os::raw::{c_int, c_ulong};
3-
use std::os::unix::io::{AsRawFd, FromRawFd};
3+
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
44

55
use libc::pid_t;
66

77
use crate::events::Event;
88
use crate::sys::bindings::perf_event_attr;
9-
use crate::{check_errno_syscall, sys, Counter, Group, SampleFlag};
9+
use crate::{check_errno_syscall, sys, Counter, SampleFlag};
1010

1111
/// A builder for [`Counter`]s.
1212
///
@@ -28,29 +28,17 @@ use crate::{check_errno_syscall, sys, Counter, Group, SampleFlag};
2828
/// # std::io::Result::Ok(())
2929
/// ```
3030
///
31-
/// The [`kind`] method lets you specify what sort of event you want to
32-
/// count. So if you'd rather count branch instructions:
33-
///
34-
/// ```
35-
/// # use perf_event::Builder;
36-
/// # use perf_event::events::Hardware;
37-
/// #
38-
/// let mut insns = Builder::new(Hardware::BRANCH_INSTRUCTIONS)
39-
/// .build()?;
40-
/// #
41-
/// # std::io::Result::Ok(())
42-
/// ```
43-
///
44-
/// The [`group`] method lets you gather individual counters into `Group`
45-
/// that can be enabled or disabled atomically:
31+
/// If you would like to gather individual counters into a [`Group`] you can
32+
/// use the [`Group::add`] method. A [`Group`] allows you to enable or disable
33+
/// all the grouped counters atomically.
4634
///
4735
/// ```
4836
/// # use perf_event::{Builder, Group};
4937
/// # use perf_event::events::Hardware;
5038
/// #
5139
/// let mut group = Group::new()?;
52-
/// let cycles = Builder::new(Hardware::CPU_CYCLES).group(&mut group).build()?;
53-
/// let insns = Builder::new(Hardware::INSTRUCTIONS).group(&mut group).build()?;
40+
/// let cycles = group.add(&Builder::new(Hardware::CPU_CYCLES))?;
41+
/// let insns = group.add(&Builder::new(Hardware::INSTRUCTIONS))?;
5442
/// #
5543
/// # std::io::Result::Ok(())
5644
/// ```
@@ -68,13 +56,12 @@ use crate::{check_errno_syscall, sys, Counter, Group, SampleFlag};
6856
/// perf_event_attr` type.
6957
///
7058
/// [`enable`]: Counter::enable
71-
/// [`kind`]: Builder::kind
72-
/// [`group`]: Builder::group
59+
/// [`Group`]: crate::Group
60+
/// [`Group::add`]: crate::Group::add
7361
pub struct Builder<'a> {
7462
attrs: perf_event_attr,
7563
who: EventPid<'a>,
7664
cpu: Option<usize>,
77-
group: Option<&'a mut Group>,
7865
}
7966

8067
#[derive(Debug)]
@@ -108,7 +95,7 @@ impl<'a> Builder<'a> {
10895
/// Return a new `Builder`, with all parameters set to their defaults.
10996
///
11097
/// Return a new `Builder` for the specified event.
111-
pub fn new(event: impl Event) -> Builder<'a> {
98+
pub fn new(event: impl Event) -> Self {
11299
let mut attrs = perf_event_attr::default();
113100

114101
// Do the update_attrs bit before we set any of the default state so
@@ -128,24 +115,23 @@ impl<'a> Builder<'a> {
128115
attrs,
129116
who: EventPid::ThisProcess,
130117
cpu: None,
131-
group: None,
132118
}
133119
}
134120

135121
/// Include kernel code.
136-
pub fn include_kernel(mut self) -> Builder<'a> {
122+
pub fn include_kernel(mut self) -> Self {
137123
self.attrs.set_exclude_kernel(0);
138124
self
139125
}
140126

141127
/// Include hypervisor code.
142-
pub fn include_hv(mut self) -> Builder<'a> {
128+
pub fn include_hv(mut self) -> Self {
143129
self.attrs.set_exclude_hv(0);
144130
self
145131
}
146132

147133
/// Observe the calling process. (This is the default.)
148-
pub fn observe_self(mut self) -> Builder<'a> {
134+
pub fn observe_self(mut self) -> Self {
149135
self.who = EventPid::ThisProcess;
150136
self
151137
}
@@ -154,7 +140,7 @@ impl<'a> Builder<'a> {
154140
/// [`CAP_SYS_PTRACE`][man-capabilities] capabilities.
155141
///
156142
/// [man-capabilities]: http://man7.org/linux/man-pages/man7/capabilities.7.html
157-
pub fn observe_pid(mut self, pid: pid_t) -> Builder<'a> {
143+
pub fn observe_pid(mut self, pid: pid_t) -> Self {
158144
self.who = EventPid::Other(pid);
159145
self
160146
}
@@ -174,7 +160,7 @@ impl<'a> Builder<'a> {
174160
/// [`build`]: Builder::build
175161
/// [`one_cpu`]: Builder::one_cpu
176162
/// [cap]: http://man7.org/linux/man-pages/man7/capabilities.7.html
177-
pub fn any_pid(mut self) -> Builder<'a> {
163+
pub fn any_pid(mut self) -> Self {
178164
self.who = EventPid::Any;
179165
self
180166
}
@@ -184,13 +170,13 @@ impl<'a> Builder<'a> {
184170
/// in the cgroupfs filesystem.
185171
///
186172
/// [man-cgroups]: http://man7.org/linux/man-pages/man7/cgroups.7.html
187-
pub fn observe_cgroup(mut self, cgroup: &'a File) -> Builder<'a> {
173+
pub fn observe_cgroup(mut self, cgroup: &'a File) -> Self {
188174
self.who = EventPid::CGroup(cgroup);
189175
self
190176
}
191177

192178
/// Observe only code running on the given CPU core.
193-
pub fn one_cpu(mut self, cpu: usize) -> Builder<'a> {
179+
pub fn one_cpu(mut self, cpu: usize) -> Self {
194180
self.cpu = Some(cpu);
195181
self
196182
}
@@ -207,7 +193,7 @@ impl<'a> Builder<'a> {
207193
/// [`observe_self`]: Builder::observe_self
208194
/// [`observe_pid`]: Builder::observe_pid
209195
/// [`observe_cgroup`]: Builder::observe_cgroup
210-
pub fn any_cpu(mut self) -> Builder<'a> {
196+
pub fn any_cpu(mut self) -> Self {
211197
self.cpu = None;
212198
self
213199
}
@@ -223,27 +209,12 @@ impl<'a> Builder<'a> {
223209
/// This flag cannot be set if the counter belongs to a `Group`. Doing so
224210
/// will result in an error when the counter is built. This is a kernel
225211
/// limitation.
226-
pub fn inherit(mut self, inherit: bool) -> Builder<'a> {
212+
pub fn inherit(mut self, inherit: bool) -> Self {
227213
let flag = if inherit { 1 } else { 0 };
228214
self.attrs.set_inherit(flag);
229215
self
230216
}
231217

232-
/// Place the counter in the given [`Group`]. Groups allow a set of counters
233-
/// to be enabled, disabled, or read as a single atomic operation, so that
234-
/// the counts can be usefully compared.
235-
///
236-
/// [`Group`]: struct.Group.html
237-
pub fn group(mut self, group: &'a mut Group) -> Builder<'a> {
238-
self.group = Some(group);
239-
240-
// man page: "Members of a group are usually initialized with disabled
241-
// set to zero."
242-
self.attrs.set_disabled(0);
243-
244-
self
245-
}
246-
247218
/// Construct a [`Counter`] according to the specifications made on this
248219
/// `Builder`.
249220
///
@@ -260,23 +231,27 @@ impl<'a> Builder<'a> {
260231
///
261232
/// [`Counter`]: struct.Counter.html
262233
/// [`enable`]: struct.Counter.html#method.enable
263-
pub fn build(mut self) -> std::io::Result<Counter> {
234+
pub fn build(&self) -> std::io::Result<Counter> {
235+
self.build_with_group(None)
236+
}
237+
238+
/// Alternative to `build` but with the group explicitly provided.
239+
///
240+
/// Used within [`Group::add`].
241+
pub(crate) fn build_with_group(&self, group_fd: Option<RawFd>) -> std::io::Result<Counter> {
264242
let cpu = match self.cpu {
265243
Some(cpu) => cpu as c_int,
266244
None => -1,
267245
};
246+
268247
let (pid, flags) = self.who.as_args();
269-
let group_fd = match self.group {
270-
Some(ref mut g) => {
271-
g.max_members += 1;
272-
g.as_raw_fd()
273-
}
274-
None => -1,
275-
};
248+
let group_fd = group_fd.unwrap_or(-1);
249+
250+
let mut attrs = self.attrs;
276251

277252
let file = unsafe {
278253
File::from_raw_fd(check_errno_syscall(|| {
279-
sys::perf_event_open(&mut self.attrs, pid, cpu, group_fd, flags as c_ulong)
254+
sys::perf_event_open(&mut attrs, pid, cpu, group_fd, flags as c_ulong)
280255
})?)
281256
};
282257

@@ -294,8 +269,8 @@ impl<'a> Builder<'a> {
294269
/// Indicate additional values to include in the generated sample events.
295270
///
296271
/// Note that this method is additive and does not remove previously added
297-
/// sample types. See the documentation of [`Sample`] or the [manpage] for
298-
/// what's available to be collected.
272+
/// sample types. See the documentation of [`SampleFlag`] or the [manpage]
273+
/// for what's available to be collected.
299274
///
300275
/// # Example
301276
/// Here we build a sampler that grabs the instruction pointer, process ID,
@@ -313,6 +288,7 @@ impl<'a> Builder<'a> {
313288
/// # Ok::<_, std::io::Error>(())
314289
/// ```
315290
///
291+
/// [`SampleFlag`]: crate::SampleFlag
316292
/// [manpage]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
317293
pub fn sample(mut self, sample: SampleFlag) -> Self {
318294
self.attrs.sample_type |= sample.bits();

perf-event/src/events.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ impl Event for Software {
182182
/// // Construct a `Group` containing the two new counters, from which we
183183
/// // can get counts over matching periods of time.
184184
/// let mut group = Group::new()?;
185-
/// let access_counter = Builder::new(ACCESS).group(&mut group).build()?;
186-
/// let miss_counter = Builder::new(MISS).group(&mut group).build()?;
185+
/// let access_counter = group.add(&Builder::new(ACCESS))?;
186+
/// let miss_counter = group.add(&Builder::new(MISS))?;
187187
/// # Ok(()) }
188188
/// ```
189189
///

0 commit comments

Comments
 (0)