pub struct Builder<'a> { /* private fields */ }Expand description
A builder for Counters.
There are dozens of parameters that influence a Counter’s behavior.
Builder lets you construct a Counter by specifying only those parameters
for which you don’t want the default value.
A freshly built Counter is disabled. To begin counting events, you must
call enable on the Counter or the Group to which it belongs.
For example, if you want a Counter for instructions retired by the current
process, those are Builder’s defaults, so you need only write:
let mut insns = Builder::new().build()?;The kind method lets you specify what sort of event you want to
count. So if you’d rather count branch instructions:
let mut insns = Builder::new()
.kind(Hardware::BRANCH_INSTRUCTIONS)
.build()?;The group method lets you gather individual counters into Group
that can be enabled or disabled atomically:
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()?;Other methods let you select:
- specific processes or cgroups to observe
- specific CPU cores to observe
Builder supports only a fraction of the many knobs and dials Linux offers,
but hopefully it will acquire methods to support more of them as time goes
on.
Internally, a Builder is just a wrapper around the kernel’s struct perf_event_attr type.
Implementations§
Source§impl<'a> Builder<'a>
impl<'a> Builder<'a>
Sourcepub fn new() -> Builder<'a>
pub fn new() -> Builder<'a>
Return a new Builder, with all parameters set to their defaults.
Examples found in repository?
3fn main() -> std::io::Result<()> {
4 let mut counter = Builder::new().build()?;
5
6 let vec = (0..=51).collect::<Vec<_>>();
7
8 counter.enable()?;
9 println!("{:?}", vec);
10 counter.disable()?;
11
12 println!("{} instructions retired", counter.read()?);
13
14 Ok(())
15}More examples
7fn main() -> std::io::Result<()> {
8 let pid: pid_t = std::env::args()
9 .nth(1)
10 .expect("Usage: insns-for-pid PID")
11 .parse()
12 .expect("Usage: insns-for-pid PID");
13
14 let mut insns = Builder::new()
15 .observe_pid(pid)
16 .kind(Hardware::BRANCH_INSTRUCTIONS)
17 .build()?;
18
19 // Count instructions in PID for five seconds.
20 insns.enable()?;
21 sleep(Duration::from_secs(5));
22 insns.disable()?;
23
24 println!("instructions in last five seconds: {}", insns.read()?);
25
26 Ok(())
27}1fn main() -> std::io::Result<()> {
2 use perf_event::events::Hardware;
3 use perf_event::{Builder, Group};
4
5 let mut group = Group::new()?;
6 let cycles = Builder::new()
7 .group(&mut group)
8 .kind(Hardware::CPU_CYCLES)
9 .build()?;
10 let insns = Builder::new()
11 .group(&mut group)
12 .kind(Hardware::INSTRUCTIONS)
13 .build()?;
14
15 let vec = (0..=51).collect::<Vec<_>>();
16
17 group.enable()?;
18 println!("{:?}", vec);
19 group.disable()?;
20
21 let counts = group.read()?;
22 println!(
23 "cycles / instructions: {} / {} ({:.2} cpi)",
24 counts[&cycles],
25 counts[&insns],
26 (counts[&cycles] as f64 / counts[&insns] as f64)
27 );
28
29 Ok(())
30}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
27 // Note that if you add more counters than you actually have hardware for,
28 // the kernel will time-slice them, which means you may get no coverage for
29 // short measurements. See the documentation.
30
31 let vec = (0..=51).collect::<Vec<_>>();
32
33 group.enable()?;
34 println!("{:?}", vec);
35 group.disable()?;
36
37 let counts = group.read()?;
38 println!(
39 "L1D cache misses/references: {} / {} ({:.0}%)",
40 counts[&miss_counter],
41 counts[&access_counter],
42 (counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0
43 );
44
45 println!(
46 "branch prediction misses/total: {} / {} ({:.0}%)",
47 counts[&missed_branches],
48 counts[&branches],
49 (counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0
50 );
51
52 // You can iterate over a `Counts` value:
53 for (id, value) in &counts {
54 println!("Counter id {} has value {}", id, value);
55 }
56
57 Ok(())
58}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}Sourcepub fn observe_self(self) -> Builder<'a>
pub fn observe_self(self) -> Builder<'a>
Observe the calling process. (This is the default.)
Sourcepub fn observe_pid(self, pid: pid_t) -> Builder<'a>
pub fn observe_pid(self, pid: pid_t) -> Builder<'a>
Observe the process with the given process id. This requires
CAP_SYS_PTRACE capabilities.
Examples found in repository?
7fn main() -> std::io::Result<()> {
8 let pid: pid_t = std::env::args()
9 .nth(1)
10 .expect("Usage: insns-for-pid PID")
11 .parse()
12 .expect("Usage: insns-for-pid PID");
13
14 let mut insns = Builder::new()
15 .observe_pid(pid)
16 .kind(Hardware::BRANCH_INSTRUCTIONS)
17 .build()?;
18
19 // Count instructions in PID for five seconds.
20 insns.enable()?;
21 sleep(Duration::from_secs(5));
22 insns.disable()?;
23
24 println!("instructions in last five seconds: {}", insns.read()?);
25
26 Ok(())
27}Sourcepub fn observe_cgroup(self, cgroup: &'a File) -> Builder<'a>
pub fn observe_cgroup(self, cgroup: &'a File) -> Builder<'a>
Observe code running in the given cgroup (container). The
cgroup argument should be a File referring to the cgroup’s directory
in the cgroupfs filesystem.
Sourcepub fn one_cpu(self, cpu: usize) -> Builder<'a>
pub fn one_cpu(self, cpu: usize) -> Builder<'a>
Observe only code running on the given CPU core.
Sourcepub fn any_cpu(self) -> Builder<'a>
pub fn any_cpu(self) -> Builder<'a>
Observe code running on any CPU core. (This is the default.)
Sourcepub fn inherit(self, inherit: bool) -> Builder<'a>
pub fn inherit(self, inherit: bool) -> Builder<'a>
Set whether this counter is inherited by new threads.
When this flag is set, this counter observes activity in new threads created by any thread already being observed.
By default, the flag is unset: counters are not inherited, and observe only the threads specified when they are created.
This flag cannot be set if the counter belongs to a Group. Doing so
will result in an error when the counter is built. This is a kernel
limitation.
Sourcepub fn kind<K: Into<Event>>(self, kind: K) -> Builder<'a>
pub fn kind<K: Into<Event>>(self, kind: K) -> Builder<'a>
Count events of the given kind. This accepts an Event value,
or any type that can be converted to one, so you can pass Hardware,
Software and Cache values directly.
The default is to count retired instructions, or
Hardware::INSTRUCTIONS events.
For example, to count level 1 data cache references and misses, pass the
appropriate events::Cache values:
use perf_event::{Builder, Group};
use perf_event::events::{Cache, CacheOp, CacheResult, WhichCache};
const ACCESS: Cache = Cache {
which: WhichCache::L1D,
operation: CacheOp::READ,
result: CacheResult::ACCESS,
};
const MISS: Cache = Cache { result: CacheResult::MISS, ..ACCESS };
let mut group = Group::new()?;
let access_counter = Builder::new().group(&mut group).kind(ACCESS).build()?;
let miss_counter = Builder::new().group(&mut group).kind(MISS).build()?;Examples found in repository?
7fn main() -> std::io::Result<()> {
8 let pid: pid_t = std::env::args()
9 .nth(1)
10 .expect("Usage: insns-for-pid PID")
11 .parse()
12 .expect("Usage: insns-for-pid PID");
13
14 let mut insns = Builder::new()
15 .observe_pid(pid)
16 .kind(Hardware::BRANCH_INSTRUCTIONS)
17 .build()?;
18
19 // Count instructions in PID for five seconds.
20 insns.enable()?;
21 sleep(Duration::from_secs(5));
22 insns.disable()?;
23
24 println!("instructions in last five seconds: {}", insns.read()?);
25
26 Ok(())
27}More examples
1fn main() -> std::io::Result<()> {
2 use perf_event::events::Hardware;
3 use perf_event::{Builder, Group};
4
5 let mut group = Group::new()?;
6 let cycles = Builder::new()
7 .group(&mut group)
8 .kind(Hardware::CPU_CYCLES)
9 .build()?;
10 let insns = Builder::new()
11 .group(&mut group)
12 .kind(Hardware::INSTRUCTIONS)
13 .build()?;
14
15 let vec = (0..=51).collect::<Vec<_>>();
16
17 group.enable()?;
18 println!("{:?}", vec);
19 group.disable()?;
20
21 let counts = group.read()?;
22 println!(
23 "cycles / instructions: {} / {} ({:.2} cpi)",
24 counts[&cycles],
25 counts[&insns],
26 (counts[&cycles] as f64 / counts[&insns] as f64)
27 );
28
29 Ok(())
30}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
27 // Note that if you add more counters than you actually have hardware for,
28 // the kernel will time-slice them, which means you may get no coverage for
29 // short measurements. See the documentation.
30
31 let vec = (0..=51).collect::<Vec<_>>();
32
33 group.enable()?;
34 println!("{:?}", vec);
35 group.disable()?;
36
37 let counts = group.read()?;
38 println!(
39 "L1D cache misses/references: {} / {} ({:.0}%)",
40 counts[&miss_counter],
41 counts[&access_counter],
42 (counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0
43 );
44
45 println!(
46 "branch prediction misses/total: {} / {} ({:.0}%)",
47 counts[&missed_branches],
48 counts[&branches],
49 (counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0
50 );
51
52 // You can iterate over a `Counts` value:
53 for (id, value) in &counts {
54 println!("Counter id {} has value {}", id, value);
55 }
56
57 Ok(())
58}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}Sourcepub fn group(self, group: &'a mut Group) -> Builder<'a>
pub fn group(self, group: &'a mut Group) -> Builder<'a>
Place the counter in the given Group. Groups allow a set of counters
to be enabled, disabled, or read as a single atomic operation, so that
the counts can be usefully compared.
Examples found in repository?
1fn main() -> std::io::Result<()> {
2 use perf_event::events::Hardware;
3 use perf_event::{Builder, Group};
4
5 let mut group = Group::new()?;
6 let cycles = Builder::new()
7 .group(&mut group)
8 .kind(Hardware::CPU_CYCLES)
9 .build()?;
10 let insns = Builder::new()
11 .group(&mut group)
12 .kind(Hardware::INSTRUCTIONS)
13 .build()?;
14
15 let vec = (0..=51).collect::<Vec<_>>();
16
17 group.enable()?;
18 println!("{:?}", vec);
19 group.disable()?;
20
21 let counts = group.read()?;
22 println!(
23 "cycles / instructions: {} / {} ({:.2} cpi)",
24 counts[&cycles],
25 counts[&insns],
26 (counts[&cycles] as f64 / counts[&insns] as f64)
27 );
28
29 Ok(())
30}More examples
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
27 // Note that if you add more counters than you actually have hardware for,
28 // the kernel will time-slice them, which means you may get no coverage for
29 // short measurements. See the documentation.
30
31 let vec = (0..=51).collect::<Vec<_>>();
32
33 group.enable()?;
34 println!("{:?}", vec);
35 group.disable()?;
36
37 let counts = group.read()?;
38 println!(
39 "L1D cache misses/references: {} / {} ({:.0}%)",
40 counts[&miss_counter],
41 counts[&access_counter],
42 (counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0
43 );
44
45 println!(
46 "branch prediction misses/total: {} / {} ({:.0}%)",
47 counts[&missed_branches],
48 counts[&branches],
49 (counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0
50 );
51
52 // You can iterate over a `Counts` value:
53 for (id, value) in &counts {
54 println!("Counter id {} has value {}", id, value);
55 }
56
57 Ok(())
58}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}Sourcepub fn build(self) -> Result<Counter>
pub fn build(self) -> Result<Counter>
Construct a Counter according to the specifications made on this
Builder.
A freshly built Counter is disabled. To begin counting events, you
must call enable on the Counter or the Group to which it belongs.
If the Builder requests features that the running kernel does not
support, it returns Err(e) where e.kind() == ErrorKind::Other and
e.raw_os_error() == Some(libc::E2BIG).
Unfortunately, problems in counter configuration are detected at this
point, by the kernel, not earlier when the offending request is made on
the Builder. The kernel’s returned errors are not always helpful.
Examples found in repository?
3fn main() -> std::io::Result<()> {
4 let mut counter = Builder::new().build()?;
5
6 let vec = (0..=51).collect::<Vec<_>>();
7
8 counter.enable()?;
9 println!("{:?}", vec);
10 counter.disable()?;
11
12 println!("{} instructions retired", counter.read()?);
13
14 Ok(())
15}More examples
7fn main() -> std::io::Result<()> {
8 let pid: pid_t = std::env::args()
9 .nth(1)
10 .expect("Usage: insns-for-pid PID")
11 .parse()
12 .expect("Usage: insns-for-pid PID");
13
14 let mut insns = Builder::new()
15 .observe_pid(pid)
16 .kind(Hardware::BRANCH_INSTRUCTIONS)
17 .build()?;
18
19 // Count instructions in PID for five seconds.
20 insns.enable()?;
21 sleep(Duration::from_secs(5));
22 insns.disable()?;
23
24 println!("instructions in last five seconds: {}", insns.read()?);
25
26 Ok(())
27}1fn main() -> std::io::Result<()> {
2 use perf_event::events::Hardware;
3 use perf_event::{Builder, Group};
4
5 let mut group = Group::new()?;
6 let cycles = Builder::new()
7 .group(&mut group)
8 .kind(Hardware::CPU_CYCLES)
9 .build()?;
10 let insns = Builder::new()
11 .group(&mut group)
12 .kind(Hardware::INSTRUCTIONS)
13 .build()?;
14
15 let vec = (0..=51).collect::<Vec<_>>();
16
17 group.enable()?;
18 println!("{:?}", vec);
19 group.disable()?;
20
21 let counts = group.read()?;
22 println!(
23 "cycles / instructions: {} / {} ({:.2} cpi)",
24 counts[&cycles],
25 counts[&insns],
26 (counts[&cycles] as f64 / counts[&insns] as f64)
27 );
28
29 Ok(())
30}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
27 // Note that if you add more counters than you actually have hardware for,
28 // the kernel will time-slice them, which means you may get no coverage for
29 // short measurements. See the documentation.
30
31 let vec = (0..=51).collect::<Vec<_>>();
32
33 group.enable()?;
34 println!("{:?}", vec);
35 group.disable()?;
36
37 let counts = group.read()?;
38 println!(
39 "L1D cache misses/references: {} / {} ({:.0}%)",
40 counts[&miss_counter],
41 counts[&access_counter],
42 (counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0
43 );
44
45 println!(
46 "branch prediction misses/total: {} / {} ({:.0}%)",
47 counts[&missed_branches],
48 counts[&branches],
49 (counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0
50 );
51
52 // You can iterate over a `Counts` value:
53 for (id, value) in &counts {
54 println!("Counter id {} has value {}", id, value);
55 }
56
57 Ok(())
58}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}