Struct perf_event::Group
source · pub struct Group { /* private fields */ }
Expand description
A group of counters that can be managed as a unit.
A Group
represents a group of Counter
s that can be enabled,
disabled, reset, or read as a single atomic operation. This is necessary if
you want to compare counter values, produce ratios, and so on, since those
operations are only meaningful on counters that cover exactly the same
period of execution.
A Counter
is placed in a group when it is created, by calling the
Builder
’s group
method. A Group
’s read
method returns values
of all its member counters at once as a Counts
value, which can be
indexed by Counter
to retrieve a specific value.
For example, the following program computes the average number of cycles
used per instruction retired for a call to println!
:
use perf_event::{Builder, Group};
use perf_event::events::Hardware;
let mut group = Group::new()?;
let cycles = Builder::new().group(&mut group).kind(Hardware::CPU_CYCLES).build()?;
let insns = Builder::new().group(&mut group).kind(Hardware::INSTRUCTIONS).build()?;
let vec = (0..=51).collect::<Vec<_>>();
group.enable()?;
println!("{:?}", vec);
group.disable()?;
let counts = group.read()?;
println!("cycles / instructions: {} / {} ({:.2} cpi)",
counts[&cycles],
counts[&insns],
(counts[&cycles] as f64 / counts[&insns] as f64));
The lifetimes of Counter
s and Group
s are independent: placing a
Counter
in a Group
does not take ownership of the Counter
, nor must
the Counter
s in a group outlive the Group
. If a Counter
is dropped, it
is simply removed from its Group
, and omitted from future results. If a
Group
is dropped, its individual counters continue to count.
Enabling or disabling a Group
affects each Counter
that belongs to it.
Subsequent reads from the Counter
will not reflect activity while the
Group
was disabled, unless the Counter
is re-enabled individually.
A Group
and its members must all observe the same tasks and cpus; mixing
these makes building the Counter
return an error. Unfortunately, there is
no way at present to specify a Group
’s task and cpu, so you can only use
Group
on the calling task. If this is a problem, please file an issue.
Internally, a Group
is just a wrapper around an event file descriptor.
Limits on group size
Hardware counters are implemented using special-purpose registers on the processor, of which there are only a fixed number. (For example, an Intel high-end laptop processor from 2015 has four such registers per virtual processor.) Without using groups, if you request more hardware counters than the processor can actually support, a complete count isn’t possible, but the kernel will rotate the processor’s real registers amongst the measurements you’ve requested to at least produce a sample.
But since the point of a counter group is that its members all cover exactly
the same period of time, this tactic can’t be applied to support large
groups. If the kernel cannot schedule a group, its counters remain zero. I
think you can detect this situation by comparing the group’s time_enabled
and time_running
values. It might also be useful to set the pinned
bit,
which puts the counter in an error state if it’s not able to be put on the
CPU; see [#10].
According to the perf_list(1)
man page, you may be able to free up a
hardware counter by disabling the kernel’s NMI watchdog, which reserves one
for detecting kernel hangs:
$ echo 0 > /proc/sys/kernel/nmi_watchdog
You can reenable the watchdog when you’re done like this:
$ echo 1 > /proc/sys/kernel/nmi_watchdog
Implementations
sourceimpl Group
impl Group
sourcepub fn enable(&mut self) -> Result<()>
pub fn enable(&mut self) -> Result<()>
Allow all Counter
s in this Group
to begin counting their designated
events, as a single atomic operation.
This does not affect whatever values the Counter
s had previously; new
events add to the current counts. To clear the Counter
s, use the
reset
method.
sourcepub fn disable(&mut self) -> Result<()>
pub fn disable(&mut self) -> Result<()>
Make all Counter
s in this Group
stop counting their designated
events, as a single atomic operation. Their counts are unaffected.
sourcepub fn reset(&mut self) -> Result<()>
pub fn reset(&mut self) -> Result<()>
Reset all Counter
s in this Group
to zero, as a single atomic operation.
sourcepub fn read(&mut self) -> Result<Counts>
pub fn read(&mut self) -> Result<Counts>
Return the values of all the Counter
s in this Group
as a Counts
value.
A Counts
value is a map from specific Counter
s to their values. You
can find a specific Counter
’s value by indexing:
let mut group = Group::new()?;
let counter1 = Builder::new().group(&mut group).kind(...).build()?;
let counter2 = Builder::new().group(&mut group).kind(...).build()?;
...
let counts = group.read()?;
println!("Rhombus inclinations per taxi medallion: {} / {} ({:.0}%)",
counts[&counter1],
counts[&counter2],
(counts[&counter1] as f64 / counts[&counter2] as f64) * 100.0);