Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for sampling #1

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ description = "A Rust interface to Linux performance monitoring"
[dependencies]
perf-event-open-sys = "1.0"
libc = "0.2"
byte = "0.2.4"
69 changes: 46 additions & 23 deletions examples/big-group.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
use perf_event::{Builder, Group};
use perf_event::events::{Cache, CacheOp, CacheResult, Hardware, WhichCache};
use perf_event::{Builder, Group};

fn main() -> std::io::Result<()> {
const ACCESS: Cache = Cache {
which: WhichCache::L1D,
operation: CacheOp::READ,
result: CacheResult::ACCESS,
};
const MISS: Cache = Cache { result: CacheResult::MISS, ..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()?;
let branches = Builder::new().group(&mut group).kind(Hardware::BRANCH_INSTRUCTIONS).build()?;
let missed_branches = Builder::new().group(&mut group).kind(Hardware::BRANCH_MISSES).build()?;
let insns = Builder::new().group(&mut group).kind(Hardware::INSTRUCTIONS).build()?;
let cycles = Builder::new().group(&mut group).kind(Hardware::CPU_CYCLES).build()?;
let access_counter = Builder::new().group(&mut group).kind(ACCESS).counter()?;
let miss_counter = Builder::new().group(&mut group).kind(MISS).counter()?;
let branches = Builder::new()
.group(&mut group)
.kind(Hardware::BRANCH_INSTRUCTIONS)
.counter()?;
let missed_branches = Builder::new()
.group(&mut group)
.kind(Hardware::BRANCH_MISSES)
.counter()?;
let insns = Builder::new()
.group(&mut group)
.kind(Hardware::INSTRUCTIONS)
.counter()?;
let cycles = Builder::new()
.group(&mut group)
.kind(Hardware::CPU_CYCLES)
.counter()?;

// Note that if you add more counters than you actually have hardware for,
// the kernel will time-slice them, which means you may get no coverage for
Expand All @@ -35,9 +50,11 @@ fn main() -> std::io::Result<()> {

let counts = group.read()?;

println!("enabled for {}ns, actually running for {}ns",
counts.time_enabled(),
counts.time_running());
println!(
"enabled for {}ns, actually running for {}ns",
counts.time_enabled(),
counts.time_running()
);

if counts.time_running() == 0 {
println!("Group was never running; no results available.");
Expand All @@ -48,20 +65,26 @@ fn main() -> std::io::Result<()> {
println!("Counts cover only a portion of the execution.");
}

println!("L1D cache misses/references: {} / {} ({:.0}%)",
counts[&miss_counter],
counts[&access_counter],
(counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0);
println!(
"L1D cache misses/references: {} / {} ({:.0}%)",
counts[&miss_counter],
counts[&access_counter],
(counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0
);

println!("branch prediction misses/total: {} / {} ({:.0}%)",
counts[&missed_branches],
counts[&branches],
(counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0);
println!(
"branch prediction misses/total: {} / {} ({:.0}%)",
counts[&missed_branches],
counts[&branches],
(counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0
);

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

// You can iterate over a `Counts` value:
for (id, value) in &counts {
Expand Down
47 changes: 28 additions & 19 deletions examples/group.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
use perf_event::{Builder, Group};
use perf_event::events::{Cache, CacheOp, CacheResult, Hardware, WhichCache};
use perf_event::{Builder, Group};

fn main() -> std::io::Result<()> {
const ACCESS: Cache = Cache {
which: WhichCache::L1D,
operation: CacheOp::READ,
result: CacheResult::ACCESS,
};
const MISS: Cache = Cache { result: CacheResult::MISS, ..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()?;
let branches = Builder::new().group(&mut group).kind(Hardware::BRANCH_INSTRUCTIONS).build()?;
let missed_branches = Builder::new().group(&mut group).kind(Hardware::BRANCH_MISSES).build()?;

// Note that if you add more counters than you actually have hardware for,
// the kernel will time-slice them, which means you may get no coverage for
// short measurements. See the documentation.
let access_counter = Builder::new().group(&mut group).kind(ACCESS).counter()?;
let miss_counter = Builder::new().group(&mut group).kind(MISS).counter()?;
let branches = Builder::new()
.group(&mut group)
.kind(Hardware::BRANCH_INSTRUCTIONS)
.counter()?;
let missed_branches = Builder::new()
.group(&mut group)
.kind(Hardware::BRANCH_MISSES)
.counter()?;

let vec = (0..=51).collect::<Vec<_>>();

Expand All @@ -26,15 +31,19 @@ fn main() -> std::io::Result<()> {
group.disable()?;

let counts = group.read()?;
println!("L1D cache misses/references: {} / {} ({:.0}%)",
counts[&miss_counter],
counts[&access_counter],
(counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0);

println!("branch prediction misses/total: {} / {} ({:.0}%)",
counts[&missed_branches],
counts[&branches],
(counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0);
println!(
"L1D cache misses/references: {} / {} ({:.0}%)",
counts[&miss_counter],
counts[&access_counter],
(counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0
);

println!(
"branch prediction misses/total: {} / {} ({:.0}%)",
counts[&missed_branches],
counts[&branches],
(counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0
);

// You can iterate over a `Counts` value:
for (id, value) in &counts {
Expand Down
4 changes: 2 additions & 2 deletions examples/insns-for-pid.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use libc::pid_t;
use perf_event::Builder;
use perf_event::events::Hardware;
use perf_event::Builder;
use std::thread::sleep;
use std::time::Duration;

Expand All @@ -14,7 +14,7 @@ fn main() -> std::io::Result<()> {
let mut insns = Builder::new()
.observe_pid(pid)
.kind(Hardware::BRANCH_INSTRUCTIONS)
.build()?;
.counter()?;

// Count instructions in PID for five seconds.
insns.enable()?;
Expand Down
22 changes: 15 additions & 7 deletions examples/println-cpi.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
fn main() -> std::io::Result<()> {
use perf_event::{Builder, Group};
use perf_event::events::Hardware;
use perf_event::{Builder, Group};

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 cycles = Builder::new()
.group(&mut group)
.kind(Hardware::CPU_CYCLES)
.counter()?;
let insns = Builder::new()
.group(&mut group)
.kind(Hardware::INSTRUCTIONS)
.counter()?;

let vec = (0..=51).collect::<Vec<_>>();

Expand All @@ -13,10 +19,12 @@ fn main() -> std::io::Result<()> {
group.disable()?;

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

Ok(())
}
2 changes: 1 addition & 1 deletion examples/println.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use perf_event::Builder;

fn main() -> std::io::Result<()> {
let mut counter = Builder::new().build()?;
let mut counter = Builder::new().counter()?;

let vec = (0..=51).collect::<Vec<_>>();

Expand Down
43 changes: 43 additions & 0 deletions examples/sample.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use perf_event::{events, sample::PerfSampleType, Builder};
use std::time::{Duration, Instant};

fn main() -> std::io::Result<()> {
let mut handles: Vec<std::thread::JoinHandle<std::io::Result<()>>> = vec![];

let end = Instant::now() + Duration::from_secs(10);

for cpu in 0..8 {
let handle = std::thread::spawn(move || {
let sample_stream = Builder::new()
.kind(events::Hardware::CPU_CYCLES)
.one_cpu(cpu)
.observe_all()
.sample(PerfSampleType::CALLCHAIN)
.sample_frequency(4000)
.sample(PerfSampleType::IP)
.sample(PerfSampleType::TID)
.sample(PerfSampleType::TIME)
.sample(PerfSampleType::CPU)
.sample(PerfSampleType::PERIOD)
.sample_stream()?;

sample_stream.enable()?;

let mut now = Instant::now();
while now < end {
if let Some(sample) = sample_stream.read(Some(end - now))? {
println!("{:#?}", sample);
}
now = Instant::now();
}

Ok(())
});
handles.push(handle);
}

for handle in handles {
handle.join().unwrap()?;
}
Ok(())
}
10 changes: 4 additions & 6 deletions src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
//! [`Cache`]: struct.Cache.html

#![allow(non_camel_case_types)]
use perf_event_open_sys::bindings as bindings;
use perf_event_open_sys::bindings;

/// Any sort of event. This is a sum of the [`Hardware`],
/// [`Software`], and [`Cache`] types, which all implement
Expand Down Expand Up @@ -211,8 +211,8 @@ impl From<Software> for Event {
/// // Construct a `Group` containing the two new counters, from which we
/// // can get counts over matching periods of time.
/// 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()?;
/// let access_counter = Builder::new().group(&mut group).kind(ACCESS).counter()?;
/// let miss_counter = Builder::new().group(&mut group).kind(MISS).counter()?;
/// # Ok(()) }
///
/// [`which`]: enum.WhichCache.html
Expand All @@ -238,9 +238,7 @@ impl From<Cache> for Event {

impl Cache {
fn as_config(&self) -> u64 {
self.which as u64 |
((self.operation as u64) << 8) |
((self.result as u64) << 16)
self.which as u64 | ((self.operation as u64) << 8) | ((self.result as u64) << 16)
}
}

Expand Down
Loading