Skip to main content

Counts

Struct Counts 

Source
pub struct Counts { /* private fields */ }
Expand description

A collection of counts from a Group of counters.

This is the type returned by calling read on a Group. You can index it with a reference to a specific Counter:

let counts = group.read()?;
println!("cycles / instructions: {} / {} ({:.2} cpi)",
         counts[&cycles],
         counts[&insns],
         (counts[&cycles] as f64 / counts[&insns] as f64));

Or you can iterate over the results it contains:

for (id, value) in &counts {
    println!("Counter id {} has value {}", id, value);
}

The id values produced by this iteration are internal identifiers assigned by the kernel. You can use the Counter::id method to find a specific counter’s id.

For some kinds of events, the kernel may use timesharing to give all counters access to scarce hardware registers. You can see how long a group was actually running versus the entire time it was enabled using the time_enabled and time_running methods:

let scale = counts.time_enabled() as f64 /
            counts.time_running() as f64;
for (id, value) in &counts {
    print!("Counter id {} has value {}",
           id, (*value as f64 * scale) as u64);
    if scale > 1.0 {
        print!(" (estimated)");
    }
    println!();
}

Implementations§

Source§

impl Counts

Source

pub fn len(&self) -> usize

Return the number of counters this Counts holds results for.

Source

pub fn time_enabled(&self) -> u64

Return the number of nanoseconds the Group was enabled that contributed to this Counts’ contents.

Examples found in repository?
examples/locality.rs (line 133)
84fn measure(label: &str, task: impl FnOnce()) {
85    use perf_event::events::{Cache, CacheOp, CacheResult, WhichCache};
86    use perf_event::{Builder, Group};
87
88    let mut group = Group::new().expect("creating group is ok");
89    let read_counter = Builder::new()
90        .group(&mut group)
91        .kind(Cache {
92            which: WhichCache::L1D,
93            operation: CacheOp::READ,
94            result: CacheResult::ACCESS,
95        })
96        .build()
97        .expect("building read_counter is ok");
98    let read_miss_counter = Builder::new()
99        .group(&mut group)
100        .kind(Cache {
101            which: WhichCache::L1D,
102            operation: CacheOp::READ,
103            result: CacheResult::MISS,
104        })
105        .build()
106        .expect("building read_miss_counter is ok");
107    let prefetch_counter = Builder::new()
108        .group(&mut group)
109        .kind(Cache {
110            which: WhichCache::L1D,
111            operation: CacheOp::PREFETCH,
112            result: CacheResult::ACCESS,
113        })
114        .build()
115        .expect("building prefetch_counter is ok");
116
117    group.enable().expect("enabling group is ok");
118    task();
119    group.disable().expect("disabling group is ok");
120
121    let counts = group.read().expect("reading group is ok");
122    let reads = counts[&read_counter];
123    let read_misses = counts[&read_miss_counter];
124    let read_hits = reads - read_misses;
125    let prefetches = counts[&prefetch_counter];
126
127    println!(
128        "{label}: hits / reads: {read_hits:8} / {reads:8} {:6.2}%, \
129         prefetched {prefetches:8}",
130        (read_hits as f64 / reads as f64) * 100.0,
131    );
132
133    if counts.time_enabled() != counts.time_running() {
134        println!(
135            "time enabled: {}  time running: {}",
136            counts.time_enabled(),
137            counts.time_running(),
138        );
139    }
140}
More examples
Hide additional examples
examples/big-group.rs (line 55)
4fn main() -> std::io::Result<()> {
5    const ACCESS: Cache = Cache {
6        which: WhichCache::L1D,
7        operation: CacheOp::READ,
8        result: CacheResult::ACCESS,
9    };
10    const MISS: Cache = Cache {
11        result: CacheResult::MISS,
12        ..ACCESS
13    };
14
15    let mut group = Group::new()?;
16    let access_counter = Builder::new().group(&mut group).kind(ACCESS).build()?;
17    let miss_counter = Builder::new().group(&mut group).kind(MISS).build()?;
18    let branches = Builder::new()
19        .group(&mut group)
20        .kind(Hardware::BRANCH_INSTRUCTIONS)
21        .build()?;
22    let missed_branches = Builder::new()
23        .group(&mut group)
24        .kind(Hardware::BRANCH_MISSES)
25        .build()?;
26    let insns = Builder::new()
27        .group(&mut group)
28        .kind(Hardware::INSTRUCTIONS)
29        .build()?;
30    let cycles = Builder::new()
31        .group(&mut group)
32        .kind(Hardware::CPU_CYCLES)
33        .build()?;
34
35    // Note that if you add more counters than you actually have hardware for,
36    // the kernel will time-slice them, which means you may get no coverage for
37    // short measurements. See the documentation.
38    //
39    // On my machine, this program won't collect any data unless I disable the
40    // NMI watchdog, as described in the documentation for `Group`. My machine
41    // has four counters, and this program tries to use all of them, but the NMI
42    // watchdog uses one up.
43
44    let mut vec = (0..=100000).collect::<Vec<_>>();
45
46    group.enable()?;
47    vec.sort();
48    println!("{:?}", &vec[0..10]);
49    group.disable()?;
50
51    let counts = group.read()?;
52
53    println!(
54        "enabled for {}ns, actually running for {}ns",
55        counts.time_enabled(),
56        counts.time_running()
57    );
58
59    if counts.time_running() == 0 {
60        println!("Group was never running; no results available.");
61        return Ok(());
62    }
63
64    if counts.time_running() < counts.time_enabled() {
65        println!("Counts cover only a portion of the execution.");
66    }
67
68    println!(
69        "L1D cache misses/references: {} / {} ({:.0}%)",
70        counts[&miss_counter],
71        counts[&access_counter],
72        (counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0
73    );
74
75    println!(
76        "branch prediction misses/total: {} / {} ({:.0}%)",
77        counts[&missed_branches],
78        counts[&branches],
79        (counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0
80    );
81
82    println!(
83        "{} instructions, {} cycles ({:.2} cpi)",
84        counts[&insns],
85        counts[&cycles],
86        counts[&cycles] as f64 / counts[&insns] as f64
87    );
88
89    // You can iterate over a `Counts` value:
90    for (id, value) in &counts {
91        println!("Counter id {} has value {}", id, value);
92    }
93
94    Ok(())
95}
Source

pub fn time_running(&self) -> u64

Return the number of nanoseconds the Group was actually collecting counts that contributed to this Counts’ contents.

Examples found in repository?
examples/locality.rs (line 133)
84fn measure(label: &str, task: impl FnOnce()) {
85    use perf_event::events::{Cache, CacheOp, CacheResult, WhichCache};
86    use perf_event::{Builder, Group};
87
88    let mut group = Group::new().expect("creating group is ok");
89    let read_counter = Builder::new()
90        .group(&mut group)
91        .kind(Cache {
92            which: WhichCache::L1D,
93            operation: CacheOp::READ,
94            result: CacheResult::ACCESS,
95        })
96        .build()
97        .expect("building read_counter is ok");
98    let read_miss_counter = Builder::new()
99        .group(&mut group)
100        .kind(Cache {
101            which: WhichCache::L1D,
102            operation: CacheOp::READ,
103            result: CacheResult::MISS,
104        })
105        .build()
106        .expect("building read_miss_counter is ok");
107    let prefetch_counter = Builder::new()
108        .group(&mut group)
109        .kind(Cache {
110            which: WhichCache::L1D,
111            operation: CacheOp::PREFETCH,
112            result: CacheResult::ACCESS,
113        })
114        .build()
115        .expect("building prefetch_counter is ok");
116
117    group.enable().expect("enabling group is ok");
118    task();
119    group.disable().expect("disabling group is ok");
120
121    let counts = group.read().expect("reading group is ok");
122    let reads = counts[&read_counter];
123    let read_misses = counts[&read_miss_counter];
124    let read_hits = reads - read_misses;
125    let prefetches = counts[&prefetch_counter];
126
127    println!(
128        "{label}: hits / reads: {read_hits:8} / {reads:8} {:6.2}%, \
129         prefetched {prefetches:8}",
130        (read_hits as f64 / reads as f64) * 100.0,
131    );
132
133    if counts.time_enabled() != counts.time_running() {
134        println!(
135            "time enabled: {}  time running: {}",
136            counts.time_enabled(),
137            counts.time_running(),
138        );
139    }
140}
More examples
Hide additional examples
examples/big-group.rs (line 56)
4fn main() -> std::io::Result<()> {
5    const ACCESS: Cache = Cache {
6        which: WhichCache::L1D,
7        operation: CacheOp::READ,
8        result: CacheResult::ACCESS,
9    };
10    const MISS: Cache = Cache {
11        result: CacheResult::MISS,
12        ..ACCESS
13    };
14
15    let mut group = Group::new()?;
16    let access_counter = Builder::new().group(&mut group).kind(ACCESS).build()?;
17    let miss_counter = Builder::new().group(&mut group).kind(MISS).build()?;
18    let branches = Builder::new()
19        .group(&mut group)
20        .kind(Hardware::BRANCH_INSTRUCTIONS)
21        .build()?;
22    let missed_branches = Builder::new()
23        .group(&mut group)
24        .kind(Hardware::BRANCH_MISSES)
25        .build()?;
26    let insns = Builder::new()
27        .group(&mut group)
28        .kind(Hardware::INSTRUCTIONS)
29        .build()?;
30    let cycles = Builder::new()
31        .group(&mut group)
32        .kind(Hardware::CPU_CYCLES)
33        .build()?;
34
35    // Note that if you add more counters than you actually have hardware for,
36    // the kernel will time-slice them, which means you may get no coverage for
37    // short measurements. See the documentation.
38    //
39    // On my machine, this program won't collect any data unless I disable the
40    // NMI watchdog, as described in the documentation for `Group`. My machine
41    // has four counters, and this program tries to use all of them, but the NMI
42    // watchdog uses one up.
43
44    let mut vec = (0..=100000).collect::<Vec<_>>();
45
46    group.enable()?;
47    vec.sort();
48    println!("{:?}", &vec[0..10]);
49    group.disable()?;
50
51    let counts = group.read()?;
52
53    println!(
54        "enabled for {}ns, actually running for {}ns",
55        counts.time_enabled(),
56        counts.time_running()
57    );
58
59    if counts.time_running() == 0 {
60        println!("Group was never running; no results available.");
61        return Ok(());
62    }
63
64    if counts.time_running() < counts.time_enabled() {
65        println!("Counts cover only a portion of the execution.");
66    }
67
68    println!(
69        "L1D cache misses/references: {} / {} ({:.0}%)",
70        counts[&miss_counter],
71        counts[&access_counter],
72        (counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0
73    );
74
75    println!(
76        "branch prediction misses/total: {} / {} ({:.0}%)",
77        counts[&missed_branches],
78        counts[&branches],
79        (counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0
80    );
81
82    println!(
83        "{} instructions, {} cycles ({:.2} cpi)",
84        counts[&insns],
85        counts[&cycles],
86        counts[&cycles] as f64 / counts[&insns] as f64
87    );
88
89    // You can iterate over a `Counts` value:
90    for (id, value) in &counts {
91        println!("Counter id {} has value {}", id, value);
92    }
93
94    Ok(())
95}
Source§

impl Counts

Source

pub fn get(&self, member: &Counter) -> Option<&u64>

Return the value recorded for member in self, or None if member is not present.

If you know that member is in the group, you can simply index:

let cycles = counts[&cycle_counter];
Source

pub fn iter<'a>(&'a self) -> CountsIter<'a>

Return an iterator over the counts in self.

for (id, value) in &counts {
    println!("Counter id {} has value {}", id, value);
}

Each item is a pair (id, &value), where id is the number assigned to the counter by the kernel (see Counter::id), and value is that counter’s value.

Trait Implementations§

Source§

impl Debug for Counts

Source§

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Index<&Counter> for Counts

Source§

type Output = u64

The returned type after indexing.
Source§

fn index(&self, index: &Counter) -> &u64

Performs the indexing (container[index]) operation. Read more
Source§

impl<'c> IntoIterator for &'c Counts

Source§

type Item = (u64, &'c u64)

The type of the elements being iterated over.
Source§

type IntoIter = CountsIter<'c>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> CountsIter<'c>

Creates an iterator from a value. Read more

Auto Trait Implementations§

§

impl Freeze for Counts

§

impl RefUnwindSafe for Counts

§

impl Send for Counts

§

impl Sync for Counts

§

impl Unpin for Counts

§

impl UnwindSafe for Counts

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

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

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.