#perf-event-open #linux #performance #perf-events #counter #hardware #size

perf-event-open

Full-featured high-level wrapper for the perf_event_open system call

4 releases (2 breaking)

new 0.2.0 Apr 14, 2025
0.1.1 Apr 13, 2025
0.0.5 Apr 12, 2025
0.0.0 Nov 4, 2024

#206 in Hardware support

Download history 2/week @ 2025-02-25 2/week @ 2025-03-04 908/week @ 2025-04-08

910 downloads per month

MIT license

610KB
4.5K SLoC

perf-event-open

Full-featured high-level wrapper for the perf_event_open system call.

Crates.io MIT licensed

perf_event_open is a Linux system call widely used in performance monitoring, which provides access to the hardware Performance Monitoring Unit (PMU), allowing us to count and sample performance events. It is the core of the perf tool and many other performance engineering utilities.

Example

Count how many instructions executed for the (inefficient) fibonacci caculation and samples the user stack for it.

use perf_event_open::config::{Cpu, Opts, Proc, SampleOn, Size};
use perf_event_open::count::Counter;
use perf_event_open::event::hw::Hardware;

// Count retired instructions on current process, all CPUs.
let event = Hardware::Instr;
let target = (Proc::CURRENT, Cpu::ALL);

let mut opts = Opts::default();
opts.sample_on = SampleOn::Freq(1000); // 1000 samples per second.
opts.sample_format.user_stack = Some(Size(8)); // Dump 8-bytes user stack in sample.

let counter = Counter::new(event, target, opts).unwrap();
let sampler = counter.sampler(10).unwrap(); // Allocate 2^10 pages to store samples.

counter.enable().unwrap(); // Start the counter.
fn fib(n: usize) -> usize {
    match n {
        0 => 0,
        1 => 1,
        n => fib(n - 1) + fib(n - 2),
    }
}
std::hint::black_box(fib(30));
counter.disable().unwrap(); // Stop the counter.

let instrs = counter.stat().unwrap().count;
println!("{} instructions retired", instrs);

for it in sampler.iter() {
    println!("{:-?}", it);
}

On my machine, this gives the following output:

73973233 instructions retired
(Kernel, Sample { record_id: RecordId { .. }, user_stack: [16, 0, 0, 0, 0, 0, 0, 0], .. })
(Kernel, Sample { record_id: RecordId { .. }, user_stack: [16, 0, 0, 0, 0, 0, 0, 0], .. })
(Kernel, Sample { record_id: RecordId { .. }, user_stack: [16, 0, 0, 0, 0, 0, 0, 0], .. })
(Kernel, Sample { record_id: RecordId { .. }, user_stack: [16, 0, 0, 0, 0, 0, 0, 0], .. })
(Kernel, Sample { record_id: RecordId { .. }, user_stack: [16, 0, 0, 0, 0, 0, 0, 0], .. })
(User, Sample { record_id: RecordId { .. }, user_stack: [2, 0, 0, 0, 0, 0, 0, 0], .. })
(User, Sample { record_id: RecordId { .. }, user_stack: [1, 0, 0, 0, 0, 0, 0, 0], .. })
(User, Sample { record_id: RecordId { .. }, user_stack: [1, 0, 0, 0, 0, 0, 0, 0], .. })

For more use cases, please check the docs.

Kernel compatibility

Any Linux kernel since 4.0 is supported.

Please use the Linux version features to ensure your binary is compatible with the target host kernel. These features are backwards compatible, e.g. linux-6.11 works with Linux 6.12 but may not work with Linux 6.10.

The legacy feature is compatible with the oldest LTS kernel that still in maintaince, or you can use the latest feature if you dont't care about the kernel compatibility.

MSRV

We will keep the MSRV (minimum supported rust version) as little as possible if no dependencies require a higher MSRV, currently 1.80.0.

License

This project is licensed under the MIT license.

Dependencies

~0.4–2.9MB
~60K SLoC