Skip to content

Commit

Permalink
fix filter handling, set num_iters
Browse files Browse the repository at this point in the history
  • Loading branch information
PSeitz committed May 16, 2024
1 parent 832dafd commit 73993e9
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 112 deletions.
42 changes: 12 additions & 30 deletions src/bench_input_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,6 @@ impl InputGroup<()> {
}
}

fn matches(input: &str, filter: &Option<String>, exact: bool) -> bool {
let Some(filter) = filter else { return true };
if exact {
input == filter
} else {
input.contains(filter)
}
}

/// Input
pub struct OwnedNamedInput<I> {
pub(crate) name: String,
Expand All @@ -60,32 +51,23 @@ impl<I: 'static> InputGroup<I> {
/// second element is the input itself.
pub(crate) fn new_with_inputs_and_options<S: Into<String>>(
inputs: Vec<(S, I)>,
mut options: Options,
options: Options,
) -> Self {
use yansi::Condition;
yansi::whenever(Condition::TTY_AND_COLOR);

let mut inputs: Vec<OwnedNamedInput<I>> = inputs
let inputs: Vec<OwnedNamedInput<I>> = inputs
.into_iter()
.map(|(name, input)| OwnedNamedInput {
name: name.into(),
data: input,
input_size_in_bytes: None,
})
.collect();
let filter_targets_input = inputs
.iter()
.any(|input| matches(&input.name, &options.filter, options.exact));
// If the filter is filtering an input, we filter and remove the filter
if filter_targets_input && options.filter.is_some() {
inputs.retain(|input| matches(&input.name, &options.filter, options.exact));
options.filter = None;
}
let mut runner = BenchRunner::new();
runner.set_options(options);

InputGroup {
inputs,
runner: BenchRunner::new(),
}
InputGroup { inputs, runner }
}
/// Set the peak mem allocator to be used for the benchmarks.
/// This will report the peak memory consumption of the benchmarks.
Expand Down Expand Up @@ -138,6 +120,13 @@ impl<I: 'static> InputGroup<I> {
self.runner.set_options(options);
}

/// Manully set the number of iterations each benchmark is called.
///
/// This disables the automatic detection of the number of iterations.
pub fn set_num_iter(&mut self, num_iter: usize) {
self.runner.set_num_iter(num_iter);
}

/// Trash CPU cache between bench runs. Defaults to false.
pub fn set_cache_trasher(&mut self, enable: bool) {
self.runner.set_cache_trasher(enable);
Expand All @@ -162,13 +151,6 @@ impl<I: 'static> InputGroup<I> {
F: Fn(&I) + 'static + Clone,
{
let name = name.into();
if !matches(
&name,
&self.runner.options.filter,
self.runner.options.exact,
) {
return;
}

for input in &self.inputs {
let named_bench: NamedBench<'static, I> =
Expand Down
66 changes: 38 additions & 28 deletions src/bench_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ pub struct BenchRunner<'a> {
/// The size of the input.
/// Enables throughput reporting.
input_size_in_bytes: Option<usize>,
/// Manully set the number of iterations each benchmark is called.
///
/// This disables the automatic detection of the number of iterations.
num_iter: Option<usize>,
}

/// Input
Expand All @@ -35,15 +39,6 @@ pub struct NamedInput<'a, I> {
pub(crate) data: &'a I,
}

fn matches(input: &str, filter: &Option<String>, exact: bool) -> bool {
let Some(filter) = filter else { return true };
if exact {
input == filter
} else {
input.contains(filter)
}
}

const EMPTY_INPUT: NamedInput<()> = NamedInput {
name: Cow::Borrowed(""),
data: &(),
Expand Down Expand Up @@ -74,6 +69,7 @@ impl<'a> BenchRunner<'a> {
alloc: None,
name: None,
input_size_in_bytes: None,
num_iter: None,
}
}
/// Set the peak mem allocator to be used for the benchmarks.
Expand Down Expand Up @@ -107,6 +103,13 @@ impl<'a> BenchRunner<'a> {
self.input_size_in_bytes = Some(input_size);
}

/// Manully set the number of iterations each benchmark is called.
///
/// This disables the automatic detection of the number of iterations.
pub fn set_num_iter(&mut self, num_iter: usize) {
self.num_iter = Some(num_iter);
}

/// Set the name of the group.
/// The name is printed before the benchmarks are run.
/// It is also used to distinguish when writing the results to disk.
Expand Down Expand Up @@ -152,15 +155,13 @@ impl<'a> BenchRunner<'a> {
F: Fn(&'a I) + 'static,
{
let name = bench_name.into();
if !matches(&name, &self.options.filter, self.options.exact) {
return;
}
let input_name = input_name.into();

let bench = NamedBench::new(name, Box::new(fun));
self.register_named_with_input(
bench,
NamedInput {
name: Cow::Owned(input_name.into()),
name: Cow::Owned(input_name),
data: input,
},
);
Expand All @@ -171,6 +172,12 @@ impl<'a> BenchRunner<'a> {
bench: NamedBench<'a, I>,
input: NamedInput<'a, I>,
) {
if let Some(filter) = &self.options.filter {
if !bench.name.contains(filter) && !input.name.contains(filter) {
return;
}
}

let bundle = InputWithBenchmark::new(
input,
self.input_size_in_bytes,
Expand All @@ -186,19 +193,8 @@ impl<'a> BenchRunner<'a> {
F: Fn(&'a ()) + 'static,
{
let name = name.into();
if !matches(&name, &self.options.filter, self.options.exact) {
return;
}

let bench = NamedBench::new(name, Box::new(fun));
let bundle = InputWithBenchmark::new(
EMPTY_INPUT,
self.input_size_in_bytes,
bench,
self.options.enable_perf,
);

self.benches.push(Box::new(bundle));
self.register_named_with_input(bench, EMPTY_INPUT);
}

/// Trash CPU cache between bench runs. Defaults to false.
Expand Down Expand Up @@ -237,7 +233,7 @@ impl<'a> BenchRunner<'a> {
// If the group is quite big, we don't want to create too big chunks, which causes
// slow tests, therefore a chunk is at most 5 elements large.
for group in group.chunks_mut(MAX_GROUP_SIZE) {
Self::warm_up_group_and_set_iter(group, self.options.verbose);
Self::warm_up_group_and_set_iter(group, self.num_iter, self.options.verbose);

if self.options.interleave {
Self::run_interleaved(
Expand Down Expand Up @@ -289,7 +285,7 @@ impl<'a> BenchRunner<'a> {
//
// This has the drawback, that one bench will affect another one.
shuffle(&mut bench_indices, iteration as u64);
std::thread::yield_now();
//std::thread::yield_now();

for bench_idx in bench_indices.iter() {
if let Some(cache_trasher) = cache_trasher {
Expand Down Expand Up @@ -321,7 +317,21 @@ impl<'a> BenchRunner<'a> {
}
}

fn warm_up_group_and_set_iter(benches: &mut [Box<dyn Bench<'a> + 'a>], verbose: bool) {
fn warm_up_group_and_set_iter(
benches: &mut [Box<dyn Bench<'a> + 'a>],
num_iter: Option<usize>,
verbose: bool,
) {
if let Some(num_iter) = num_iter {
if verbose {
println!("Manually set num iterations to {}", num_iter);
}

for input_and_bench in benches {
input_and_bench.set_num_iter(num_iter);
}
return;
}
// In order to make the benchmarks in a group comparable, it is imperative to call them
// the same numer of times
let (min_num_iter, max_num_iter) =
Expand Down
104 changes: 50 additions & 54 deletions src/profiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,41 @@ pub trait Profiler {

#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct CounterValues {
/// Level 1 Data Cache Accesses
pub l1d_access_count: f64,
/// Level 1 Data Cache Misses
pub l1d_miss_count: f64,
/// TLB Data Cache Accesses
pub tlbd_access_count: f64,
/// TLB Data Cache Misses
pub tlbd_miss_count: f64,
pub branches_count: f64,
pub missed_branches_count: f64,
}

/// Print Counter value
fn print_counter_value<F: Fn(&CounterValues) -> f64>(
name: &str,
stats: &CounterValues,
other: Option<CounterValues>,
f: F,
) -> String {
let diff_str = other
.as_ref()
.map(|other| {
if f(other) == 0.0 || f(stats) == 0.0 || f(other) == f(stats) {
return "".to_string();
}

let val = f(stats);
let other = f(other);
format_percentage(compute_percentage_diff(val, other), true)
})
.unwrap_or_default();

format!("{}: {:.3} {}", name, f(stats), diff_str,)
}

impl CounterValues {
#[allow(dead_code)]
pub fn print_legend() {
Expand All @@ -41,61 +70,28 @@ impl CounterValues {

// Method to compare two `CounterValues` instances and return columns
pub fn to_columns(self, other: Option<CounterValues>) -> Vec<String> {
let l1d_access_count_diff = other
.as_ref()
.map(|other| {
format_percentage(
compute_percentage_diff(self.l1d_access_count, other.l1d_access_count),
true,
)
})
.unwrap_or_default();
let l1d_miss_count_diff = other
.as_ref()
.map(|other| {
format_percentage(
compute_percentage_diff(self.l1d_miss_count, other.l1d_miss_count),
true,
)
})
.unwrap_or_default();
let branches_count_diff = other
.as_ref()
.map(|other| {
format_percentage(
compute_percentage_diff(self.branches_count, other.branches_count),
true,
)
})
.unwrap_or_default();
let missed_branches_count_diff = other
.as_ref()
.map(|other| {
format_percentage(
compute_percentage_diff(
self.missed_branches_count,
other.missed_branches_count,
),
true,
)
})
.unwrap_or_default();

let l1da = format!(
"L1dA: {:.3} {}",
self.l1d_access_count, l1d_access_count_diff,
);
let l1dm = format!("L1dM: {:.3} {}", self.l1d_miss_count, l1d_miss_count_diff);
let branches = format!("Br: {:.3} {}", self.branches_count, branches_count_diff);
let branches_missed = format!(
"BrM: {:.3} {}",
self.missed_branches_count, missed_branches_count_diff
);
vec![
l1da.red().to_string(),
l1dm.green().to_string(),
branches.blue().to_string(),
branches_missed.red().to_string(),
print_counter_value("L1dA", &self, other, |stats| stats.l1d_access_count)
.red()
.to_string(),
print_counter_value("L1dM", &self, other, |stats| stats.l1d_miss_count)
.green()
.to_string(),
print_counter_value("TLBdA", &self, other, |stats| stats.tlbd_access_count)
.red()
.to_string(),
print_counter_value("TLBdM", &self, other, |stats| stats.tlbd_miss_count)
.red()
.to_string(),
print_counter_value("L1dA", &self, other, |stats| stats.l1d_access_count)
.red()
.to_string(),
print_counter_value("Br", &self, other, |stats| stats.branches_count)
.blue()
.to_string(),
print_counter_value("MBr", &self, other, |stats| stats.missed_branches_count)
.red()
.to_string(),
]
}
}
Loading

0 comments on commit 73993e9

Please sign in to comment.