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 Counters 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 Counters and Groups are independent: placing a Counter in a Group does not take ownership of the Counter, nor must the Counters 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

Construct a new, empty Group.

Allow all Counters in this Group to begin counting their designated events, as a single atomic operation.

This does not affect whatever values the Counters had previously; new events add to the current counts. To clear the Counters, use the reset method.

Make all Counters in this Group stop counting their designated events, as a single atomic operation. Their counts are unaffected.

Reset all Counters in this Group to zero, as a single atomic operation.

Return the values of all the Counters in this Group as a Counts value.

A Counts value is a map from specific Counters 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);

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.