From 836ccd453a116e6bcffed31107105a9e930e0ad4 Mon Sep 17 00:00:00 2001 From: Pascal Seitz Date: Mon, 14 Oct 2024 18:27:42 +0800 Subject: [PATCH] move cache trasher to plugins, refactor plugins --- README.md | 6 ++- benches/bench_group.rs | 6 ++- benches/bench_input.rs | 6 ++- benches/test_throughput.rs | 6 ++- src/bench.rs | 20 ++++---- src/bench_input_group.rs | 10 ++-- src/bench_runner.rs | 76 ++++++------------------------- src/config.rs | 9 ---- src/lib.rs | 6 ++- src/plugins/alloc.rs | 8 ++-- src/plugins/cache_trasher.rs | 52 +++++++++++++++++++++ src/plugins/events.rs | 73 ++++++++++++++++------------- src/plugins/mod.rs | 13 +++--- src/plugins/perf_counter/linux.rs | 16 +++---- src/report/mod.rs | 8 ++-- src/report/plain_reporter.rs | 23 +++++++--- src/report/table_reporter.rs | 10 ++-- 17 files changed, 187 insertions(+), 161 deletions(-) create mode 100644 src/plugins/cache_trasher.rs diff --git a/README.md b/README.md index 426881a..cc2987b 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ It is designed to be simple to use and to provide a good overview of the perform ### Example ```rust -use binggan::{black_box, InputGroup, PeakMemAlloc, INSTRUMENTED_SYSTEM}; +use binggan::{black_box, plugins::CacheTrasher, InputGroup, PeakMemAlloc, INSTRUMENTED_SYSTEM}; #[global_allocator] pub static GLOBAL: &PeakMemAlloc = &INSTRUMENTED_SYSTEM; @@ -46,7 +46,9 @@ fn bench_group(mut runner: InputGroup>) { // Enables the perf integration. Only on Linux, noop on other OS. runner.config().enable_perf(); // Trashes the CPU cache between runs - runner.config().set_cache_trasher(true); + runner + .get_plugin_manager() + .add_plugin(CacheTrasher::default()); // Enables throughput reporting runner.throughput(|input| input.len() * std::mem::size_of::()); runner.register("vec", |data| { diff --git a/benches/bench_group.rs b/benches/bench_group.rs index e60c43d..0f9e361 100644 --- a/benches/bench_group.rs +++ b/benches/bench_group.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use binggan::{black_box, BenchRunner, PeakMemAlloc, INSTRUMENTED_SYSTEM}; +use binggan::{black_box, plugins::CacheTrasher, BenchRunner, PeakMemAlloc, INSTRUMENTED_SYSTEM}; #[global_allocator] pub static GLOBAL: &PeakMemAlloc = &INSTRUMENTED_SYSTEM; @@ -35,7 +35,9 @@ fn run_bench() { runner.set_alloc(GLOBAL); // Set the peak mem allocator. This will enable peak memory reporting. runner.config().enable_perf(); - runner.config().set_cache_trasher(true); + runner + .get_plugin_manager() + .add_plugin(CacheTrasher::default()); for (input_name, data) in inputs.iter() { let mut group = runner.new_group(); diff --git a/benches/bench_input.rs b/benches/bench_input.rs index 9c15411..3958e62 100644 --- a/benches/bench_input.rs +++ b/benches/bench_input.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use binggan::{black_box, InputGroup, PeakMemAlloc, INSTRUMENTED_SYSTEM}; +use binggan::{black_box, plugins::CacheTrasher, InputGroup, PeakMemAlloc, INSTRUMENTED_SYSTEM}; #[global_allocator] pub static GLOBAL: &PeakMemAlloc = &INSTRUMENTED_SYSTEM; @@ -29,7 +29,9 @@ fn bench_group(mut runner: InputGroup, u64>) { // Enables the perf integration. Only on Linux, noop on other OS. runner.config().enable_perf(); // Trashes the CPU cache between runs - runner.config().set_cache_trasher(true); + runner + .get_plugin_manager() + .add_plugin(CacheTrasher::default()); // Enables throughput reporting runner.throughput(|input| input.len() * std::mem::size_of::()); runner.register("vec", |data| { diff --git a/benches/test_throughput.rs b/benches/test_throughput.rs index 352ef2c..b933b6c 100644 --- a/benches/test_throughput.rs +++ b/benches/test_throughput.rs @@ -1,6 +1,6 @@ use std::time::{Duration, Instant}; -use binggan::{BenchRunner, PeakMemAlloc, INSTRUMENTED_SYSTEM}; +use binggan::{plugins::CacheTrasher, BenchRunner, PeakMemAlloc, INSTRUMENTED_SYSTEM}; #[global_allocator] pub static GLOBAL: &PeakMemAlloc = &INSTRUMENTED_SYSTEM; @@ -10,7 +10,9 @@ fn run_bench() { runner.set_alloc(GLOBAL); // Set the peak mem allocator. This will enable peak memory reporting. runner.config().enable_perf(); - runner.config().set_cache_trasher(true); + runner + .get_plugin_manager() + .add_plugin(CacheTrasher::default()); runner.config().set_num_iter_for_group(128); let mut group = runner.new_group(); diff --git a/src/bench.rs b/src/bench.rs index 6301446..1657571 100644 --- a/src/bench.rs +++ b/src/bench.rs @@ -13,8 +13,8 @@ pub trait Bench<'a> { fn set_num_iter(&mut self, num_iter: usize); /// Sample the number of iterations the benchmark should do fn sample_num_iter(&mut self) -> usize; - fn exec_bench(&mut self, events: &mut EventManager); - fn get_results(&mut self, events: &mut EventManager) -> BenchResult; + fn exec_bench(&mut self, events: &mut PluginManager); + fn get_results(&mut self, events: &mut PluginManager) -> BenchResult; fn clear_results(&mut self); } @@ -102,17 +102,17 @@ impl<'a, I, O: OutputValue> Bench<'a> for InputWithBenchmark<'a, I, O> { } #[inline] - fn exec_bench(&mut self, events: &mut EventManager) { + fn exec_bench(&mut self, events: &mut PluginManager) { let num_iter = self.get_num_iter_or_fail(); let res = self.bench.exec_bench(self.input, num_iter, events); self.results.push(res); } - fn get_results(&mut self, events: &mut EventManager) -> BenchResult { + fn get_results(&mut self, events: &mut PluginManager) -> BenchResult { let num_iter = self.get_num_iter_or_fail(); let total_num_iter = self.bench.num_group_iter as u64 * num_iter as u64; let memory_consumption: Option<&Vec> = events - .downcast_listener::(ALLOC_EVENT_LISTENER_NAME) + .downcast_plugin::(ALLOC_EVENT_LISTENER_NAME) .and_then(|counters| counters.get_by_bench_id(&self.bench.bench_id)); let stats = compute_stats(&self.results, memory_consumption); let tracked_memory = memory_consumption.is_some(); @@ -137,14 +137,14 @@ impl<'a, I, O: OutputValue> Bench<'a> for InputWithBenchmark<'a, I, O> { } fn get_perf_counter( - _events: &mut EventManager, + _events: &mut PluginManager, _bench_id: &BenchId, _total_num_iter: u64, ) -> Option { #[cfg(target_os = "linux")] { _events - .downcast_listener::(PERF_CNT_EVENT_LISTENER_NAME) + .downcast_plugin::(PERF_CNT_EVENT_LISTENER_NAME) .and_then(|counters| { counters .get_by_bench_id_mut(_bench_id) @@ -211,9 +211,9 @@ impl<'a, I, O> NamedBench<'a, I, O> { &mut self, input: &'a I, num_iter: usize, - events: &mut EventManager, + events: &mut PluginManager, ) -> RunResult { - events.emit(BingganEvents::BenchStart { + events.emit(PluginEvents::BenchStart { bench_id: &self.bench_id, }); let start = std::time::Instant::now(); @@ -224,7 +224,7 @@ impl<'a, I, O> NamedBench<'a, I, O> { let elapsed = start.elapsed(); let run_result = RunResult::new(elapsed.as_nanos() as u64 / num_iter as u64, res); - events.emit(BingganEvents::BenchStop { + events.emit(PluginEvents::BenchStop { bench_id: &self.bench_id, duration: run_result.duration_ns, }); diff --git a/src/bench_input_group.rs b/src/bench_input_group.rs index c09882d..b654182 100644 --- a/src/bench_input_group.rs +++ b/src/bench_input_group.rs @@ -1,7 +1,7 @@ use std::{alloc::GlobalAlloc, mem}; use crate::output_value::OutputValue; -use crate::plugins::EventManager; +use crate::plugins::PluginManager; use crate::{ bench::NamedBench, bench_id::BenchId, bench_runner::BenchRunner, parse_args, BenchGroup, Config, }; @@ -152,10 +152,10 @@ impl InputGroup { &mut self.runner.config } - /// Returns the event manager, which can be used to add listeners to the benchmarks. - /// See [crate::plugins::EventManager] for more information. - pub fn get_event_manager(&mut self) -> &mut EventManager { - self.runner.get_event_manager() + /// Returns the plugin manager, which can be used to add plugins. + /// See [crate::plugins::PluginManager] for more information. + pub fn get_plugin_manager(&mut self) -> &mut PluginManager { + self.runner.get_plugin_manager() } } diff --git a/src/bench_runner.rs b/src/bench_runner.rs index 4ba388f..e5d36c6 100644 --- a/src/bench_runner.rs +++ b/src/bench_runner.rs @@ -3,7 +3,7 @@ use std::{alloc::GlobalAlloc, cmp::Ordering}; use crate::output_value::OutputValue; use crate::plugins::alloc::AllocPerBench; -use crate::plugins::{BingganEvents, EventManager}; +use crate::plugins::{PluginEvents, PluginManager}; use crate::report::PlainReporter; use crate::{ bench::{Bench, InputWithBenchmark, NamedBench}, @@ -12,13 +12,11 @@ use crate::{ report::report_group, BenchGroup, Config, }; -use core::mem::size_of; use peakmem_alloc::*; /// The main struct to run benchmarks. /// pub struct BenchRunner { - cache_trasher: CacheTrasher, pub(crate) config: Config, /// The size of the input. /// Enables throughput reporting. @@ -27,7 +25,7 @@ pub struct BenchRunner { /// Name of the test pub(crate) name: Option, - listeners: EventManager, + listeners: PluginManager, } pub const EMPTY_INPUT: &() = &(); @@ -51,9 +49,9 @@ impl BenchRunner { new } - /// Returns the event manager, which can be used to add listeners to the benchmarks. - /// See [crate::plugins::EventManager] for more information. - pub fn get_event_manager(&mut self) -> &mut EventManager { + /// Returns the plugin manager, which can be used to add plugins. + /// See [crate::plugins::PluginManager] for more information. + pub fn get_plugin_manager(&mut self) -> &mut PluginManager { &mut self.listeners } @@ -62,11 +60,10 @@ impl BenchRunner { use yansi::Condition; yansi::whenever(Condition::TTY_AND_COLOR); - let mut event_manager = EventManager::new(); - event_manager.add_listener_if_absent(PlainReporter::new()); + let mut event_manager = PluginManager::new(); + event_manager.add_plugin_if_absent(PlainReporter::new()); BenchRunner { - cache_trasher: CacheTrasher::new(1024 * 1024 * 16), config: options, input_size_in_bytes: None, name: None, @@ -91,7 +88,7 @@ impl BenchRunner { /// This will report the peak memory consumption of the benchmarks. pub fn set_alloc(&mut self, alloc: &'static PeakMemAlloc) { let alloc = AllocPerBench::new(alloc); - self.listeners.add_listener_if_absent(alloc); + self.listeners.add_plugin_if_absent(alloc); } /// Enables throughput reporting. The throughput will be valid for all inputs that are @@ -147,11 +144,11 @@ impl BenchRunner { use crate::plugins::perf_counter::PerfCounterPerBench; if self.config().enable_perf { self.listeners - .add_listener_if_absent(PerfCounterPerBench::default()); + .add_plugin_if_absent(PerfCounterPerBench::default()); } } - self.listeners.emit(BingganEvents::GroupStart { + self.listeners.emit(PluginEvents::GroupStart { runner_name: self.name.as_deref(), group_name, output_value_column_title, @@ -172,12 +169,7 @@ impl BenchRunner { Self::detect_and_set_num_iter(group, self.config.verbose, &mut self.listeners); if self.config.interleave { - Self::run_interleaved( - group, - self.config.cache_trasher.then_some(&self.cache_trasher), - num_group_iter, - &mut self.listeners, - ); + Self::run_interleaved(group, num_group_iter, &mut self.listeners); } else { Self::run_sequential(group, num_group_iter, &mut self.listeners); } @@ -200,7 +192,7 @@ impl BenchRunner { fn run_sequential<'a>( benches: &mut [Box + 'a>], num_group_iter: usize, - events: &mut EventManager, + events: &mut PluginManager, ) { for bench in benches { for iteration in 0..num_group_iter { @@ -217,9 +209,8 @@ impl BenchRunner { fn run_interleaved<'a>( benches: &mut [Box + 'a>], - cache_trasher: Option<&CacheTrasher>, num_group_iter: usize, - events: &mut EventManager, + events: &mut PluginManager, ) { let mut bench_indices: Vec = (0..benches.len()).collect(); for iteration in 0..num_group_iter { @@ -229,9 +220,6 @@ impl BenchRunner { shuffle(&mut bench_indices, iteration as u64); for bench_idx in bench_indices.iter() { - if let Some(cache_trasher) = cache_trasher { - cache_trasher.issue_read(); - } let bench = &mut benches[*bench_idx]; // We use alloca to address memory layout randomness issues // So the whole stack moves down by 1 byte for each iteration @@ -262,7 +250,7 @@ impl BenchRunner { fn detect_and_set_num_iter<'b>( benches: &mut [Box + 'b>], verbose: bool, - events: &mut EventManager, + events: &mut PluginManager, ) { if let Some(num_iter) = env::var("NUM_ITER_BENCH") .ok() @@ -297,7 +285,7 @@ impl BenchRunner { let max_num_iter = max_num_iter.min(min_num_iter * 10); // We round up, so that we may get the same number of iterations between runs let max_num_iter = round_up(max_num_iter as u64) as usize; - events.emit(BingganEvents::GroupNumIters { + events.emit(PluginEvents::GroupNumIters { num_iter: max_num_iter, }); if verbose { @@ -353,40 +341,6 @@ where Some((min_so_far, max_so_far)) } -/// Performs a dummy reads from memory to spoil given amount of CPU cache -/// -/// Uses cache aligned data arrays to perform minimum amount of reads possible to spoil the cache -#[derive(Clone)] -struct CacheTrasher { - cache_lines: Vec, -} -impl Default for CacheTrasher { - fn default() -> Self { - Self::new(1024 * 1024 * 16) // 16MB - } -} - -impl CacheTrasher { - fn new(bytes: usize) -> Self { - let n = bytes / size_of::(); - let cache_lines = vec![CacheLine::default(); n]; - Self { cache_lines } - } - - fn issue_read(&self) { - for line in &self.cache_lines { - // Because CacheLine is aligned on 64 bytes it is enough to read single element from the array - // to spoil the whole cache line - unsafe { std::ptr::read_volatile(&line.0[0]) }; - } - } -} - -#[repr(C)] -#[repr(align(64))] -#[derive(Default, Clone, Copy)] -struct CacheLine([u16; 32]); - fn shuffle(indices: &mut [usize], seed: u64) { let mut rng = SimpleRng::new(seed); diff --git a/src/config.rs b/src/config.rs index 104c1c7..341895e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,8 +10,6 @@ pub struct Config { pub filter: Option, /// Enable/disable perf integration pub enable_perf: bool, - /// Trash CPU cache between bench runs. - pub cache_trasher: bool, /// Verbose output of binggan. Prints the number of iterations. pub verbose: bool, /// Manually set the number of iterations the benchmarks registered afterwards are called. @@ -29,7 +27,6 @@ impl Default for Config { interleave: true, filter: None, enable_perf: false, - cache_trasher: false, verbose: false, num_iter_bench: None, num_iter_group: None, @@ -117,12 +114,6 @@ impl Config { self.enable_perf = true; self } - - /// Trash CPU cache between bench runs. Defaults to false. - pub fn set_cache_trasher(&mut self, enable: bool) -> &mut Self { - self.cache_trasher = enable; - self - } } pub(crate) fn parse_args() -> Config { diff --git a/src/lib.rs b/src/lib.rs index d8f7bd2..0d4b494 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,7 +101,7 @@ //! ``` //! use std::collections::HashMap; //! -//! use binggan::{black_box, BenchRunner, PeakMemAlloc, INSTRUMENTED_SYSTEM}; +//! use binggan::{black_box, plugins::*, BenchRunner, PeakMemAlloc, INSTRUMENTED_SYSTEM}; //! //! #[global_allocator] //! pub static GLOBAL: &PeakMemAlloc = &INSTRUMENTED_SYSTEM; @@ -136,7 +136,9 @@ //! runner.set_alloc(GLOBAL); // Set the peak mem allocator. This will enable peak memory reporting. //! //! runner.config().enable_perf(); -//! runner.config().set_cache_trasher(true); +//! runner +//! .get_plugin_manager() +//! .add_plugin(CacheTrasher::default()); //! //! let mut group = runner.new_group(); //! for (input_name, data) in inputs.iter() { diff --git a/src/plugins/alloc.rs b/src/plugins/alloc.rs index f710a27..1c2b765 100644 --- a/src/plugins/alloc.rs +++ b/src/plugins/alloc.rs @@ -4,7 +4,7 @@ use peakmem_alloc::PeakMemAllocTrait; use crate::{ bench_id::BenchId, - plugins::{BingganEvents, EventListener, PerBenchData}, + plugins::{EventListener, PerBenchData, PluginEvents}, }; /// Integration via EventListener @@ -37,13 +37,13 @@ impl EventListener for AllocPerBench { fn name(&self) -> &'static str { ALLOC_EVENT_LISTENER_NAME } - fn on_event(&mut self, event: BingganEvents) { + fn on_event(&mut self, event: PluginEvents) { match event { - BingganEvents::BenchStart { bench_id } => { + PluginEvents::BenchStart { bench_id } => { self.alloc_per_bench.insert_if_absent(bench_id, Vec::new); self.alloc.reset_peak_memory(); } - BingganEvents::BenchStop { bench_id, .. } => { + PluginEvents::BenchStop { bench_id, .. } => { let perf = self.alloc_per_bench.get_mut(bench_id).unwrap(); perf.push(self.alloc.get_peak_memory()); } diff --git a/src/plugins/cache_trasher.rs b/src/plugins/cache_trasher.rs new file mode 100644 index 0000000..c832f99 --- /dev/null +++ b/src/plugins/cache_trasher.rs @@ -0,0 +1,52 @@ +use super::{EventListener, PluginEvents}; + +/// Performs a dummy reads from memory to spoil given amount of CPU cache +/// +/// Uses cache aligned data arrays to perform minimum amount of reads possible to spoil the cache +#[derive(Clone)] +pub struct CacheTrasher { + cache_lines: Vec, +} +impl Default for CacheTrasher { + fn default() -> Self { + Self::new(1024 * 1024 * 16) // 16MB + } +} + +impl CacheTrasher { + /// Creates a new instance of `CacheTrasher`. + /// + /// The `bytes` parameter is the amount of memory to read to spoil the cache. + pub fn new(bytes: usize) -> Self { + let n = bytes / size_of::(); + let cache_lines = vec![CacheLine::default(); n]; + Self { cache_lines } + } + + fn issue_read(&self) { + for line in &self.cache_lines { + // Because CacheLine is aligned on 64 bytes it is enough to read single element from the array + // to spoil the whole cache line + unsafe { std::ptr::read_volatile(&line.0[0]) }; + } + } +} + +#[repr(C)] +#[repr(align(64))] +#[derive(Default, Clone, Copy)] +struct CacheLine([u16; 32]); + +impl EventListener for CacheTrasher { + fn as_any(&mut self) -> &mut dyn std::any::Any { + self + } + fn name(&self) -> &'static str { + "cache_trasher" + } + fn on_event(&mut self, event: PluginEvents) { + if let PluginEvents::BenchStart { bench_id: _ } = event { + self.issue_read(); + } + } +} diff --git a/src/plugins/events.rs b/src/plugins/events.rs index 14cca06..475411b 100644 --- a/src/plugins/events.rs +++ b/src/plugins/events.rs @@ -1,9 +1,9 @@ -//! Event manager for Binggan. -//! The event manager is responsible for managing event listeners and emitting events. -//! It is used to notify listeners about events that occur during the benchmark run. +//! [PluginManager] for Binggan. +//! The plugin manager is responsible for managing plugins and emitting events to them +//! that occur during the benchmark run. //! -//! See the `BingganEvents` enum for the list of events that can be emitted. -//! Any type that implements the `EventListener` trait can be added to the event manager. +//! See the `PluginEvents` enum for the list of events that can be emitted. +//! Any type that implements the `EventListener` trait can be added to [PluginManager]. //! use crate::{bench::BenchResult, bench_id::BenchId}; @@ -12,7 +12,7 @@ use std::any::Any; /// Events that can be emitted by the benchmark runner. #[derive(Debug, Clone, Copy)] -pub enum BingganEvents<'a> { +pub enum PluginEvents<'a> { /// The number of iterations for a group has been set. /// The previous event was `GroupStart`. GroupNumIters { @@ -64,71 +64,80 @@ pub trait EventListener: Any { /// The name of the event listener. fn name(&self) -> &'static str; /// Handle an event. - /// See the [BingganEvents] enum for the list of events that can be emitted. - fn on_event(&mut self, event: BingganEvents); + /// See the [PluginEvents] enum for the list of events that can be emitted. + fn on_event(&mut self, event: PluginEvents); /// Downcast the listener to `Any`. fn as_any(&mut self) -> &mut dyn Any; } -/// The event manager is responsible for managing event listeners and emitting events. -/// It is used to notify listeners about events that occur during the benchmark run. +/// [PluginManager] is responsible for managing plugins and emitting events. /// -/// See the `BingganEvents` enum for the list of events that can be emitted. -/// Any type that implements the `EventListener` trait can be added to the event manager. -pub struct EventManager { +/// See the [PluginEvents] enum for the list of events that can be emitted. +/// Any type that implements the `EventListener` trait can be added to the plugin manager. +pub struct PluginManager { listeners: Vec<(String, Box)>, } -impl EventManager { - /// Create a new instance of `EventManager`. +impl PluginManager { + /// Create a new instance of [PluginManager]. pub fn new() -> Self { Self { listeners: Vec::new(), } } - /// Removes any listeners with the same name and sets the new listener. - pub fn replace_listener(&mut self, listener: L) { - self.remove_listener_by_name(listener.name()); + /// Removes any plugins with the same name and sets the new listener. + pub fn replace_plugin(&mut self, listener: L) -> &mut Self { + self.remove_plugin_by_name(listener.name()); self.listeners .push((listener.name().to_owned(), Box::new(listener))); + self } - /// Add a new listener to the event manager if it is not already present by name. - pub fn add_listener_if_absent(&mut self, listener: L) { - if self.get_listener(listener.name()).is_some() { - return; + /// Add a new plugin. Note that this will not remove listeners with the + /// same name. + pub fn add_plugin(&mut self, listener: L) -> &mut Self { + self.listeners + .push((listener.name().to_owned(), Box::new(listener))); + self + } + + /// Add a new plugin to the plugin manager if it is not already present by name. + pub fn add_plugin_if_absent(&mut self, listener: L) -> &mut Self { + if self.get_plugins(listener.name()).is_some() { + return self; } self.listeners .push((listener.name().to_owned(), Box::new(listener))); + self } - /// Get a listener by name. - pub fn get_listener(&mut self, name: &str) -> Option<&mut Box> { + /// Get the first plugin that matches the name. + pub fn get_plugins(&mut self, name: &str) -> Option<&mut Box> { self.listeners .iter_mut() .find(|(n, _)| n == name) .map(|(_, l)| l) } - /// Downcast a listener to a specific type. - pub fn downcast_listener(&mut self, name: &str) -> Option<&mut T> { - self.get_listener(name)?.as_any().downcast_mut::() + /// Downcast a plugin to a specific type. + pub fn downcast_plugin(&mut self, name: &str) -> Option<&mut T> { + self.get_plugins(name)?.as_any().downcast_mut::() } - /// Remove a listener by name. - pub fn remove_listener_by_name(&mut self, name: &str) { + /// Remove a plugin by name. + pub fn remove_plugin_by_name(&mut self, name: &str) { self.listeners.retain(|(n, _)| n != name); } - /// Emit an event to all listeners. - pub fn emit(&mut self, event: BingganEvents) { + /// Emit an event to all plugin. + pub fn emit(&mut self, event: PluginEvents) { for (_, listener) in self.listeners.iter_mut() { listener.on_event(event); } } } -impl Default for EventManager { +impl Default for PluginManager { fn default() -> Self { Self::new() } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 70740a1..6a1bef4 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,9 +1,9 @@ //! The plugin system works by registering to events. //! -//! The `BingganEvents` enum contains all the events that can be emitted. +//! The `PluginEvents` enum contains all the events that can be emitted. //! The `EventListener` trait is used to listen to these events. //! -//! The `BenchRunner` has an `EventManager` which can be used to add listeners. +//! The `BenchRunner` has an `PluginManager` which can be used to add plugins. //! The listeners can be used to track memory consumption, report results, etc. //! //! `name` is used to identify the listener. @@ -19,9 +19,9 @@ //! fn name(&self) -> &'static str { //! "my_listener" //! } -//! fn on_event(&mut self, event: BingganEvents) { +//! fn on_event(&mut self, event: PluginEvents) { //! match event { -//! BingganEvents::GroupStart{runner_name, ..} => { +//! PluginEvents::GroupStart{runner_name, ..} => { //! println!("Starting: {:?}", runner_name); //! } //! _ => {} @@ -32,13 +32,13 @@ //! } //! } //! let mut runner = BenchRunner::new(); -//! let events = runner.get_event_manager(); -//! events.add_listener_if_absent(MyListener); +//! runner.get_plugin_manager().add_plugin(MyListener); //! //! ``` //! pub(crate) mod alloc; +mod cache_trasher; pub mod events; pub(crate) mod perf_counter; @@ -46,4 +46,5 @@ pub(crate) mod perf_counter; #[cfg(target_os = "linux")] pub use perf_counter::*; +pub use cache_trasher::*; pub use events::*; diff --git a/src/plugins/perf_counter/linux.rs b/src/plugins/perf_counter/linux.rs index 9ddf9d9..7c31259 100644 --- a/src/plugins/perf_counter/linux.rs +++ b/src/plugins/perf_counter/linux.rs @@ -2,7 +2,7 @@ use std::error::Error; use crate::bench_id::BenchId; -use crate::plugins::{BingganEvents, EventListener, PerBenchData}; +use crate::plugins::{EventListener, PerBenchData, PluginEvents}; use perf_event::events::{Cache, CacheOp, CacheResult, Hardware, WhichCache}; use perf_event::Counter; use perf_event::{Builder, Group}; @@ -11,14 +11,14 @@ use std::any::Any; use super::CounterValues; pub(crate) struct PerfCounters { + branches: Counter, + branches_missed: Counter, group: Group, // translation lookaside buffer tlbd_access_counter: Counter, tlbd_miss_counter: Counter, l1d_access_counter: Counter, l1d_miss_counter: Counter, - branches: Counter, - branch_misses: Counter, } impl PerfCounters { pub fn new() -> Result> { @@ -65,7 +65,7 @@ impl PerfCounters { l1d_access_counter, l1d_miss_counter, branches, - branch_misses: missed_branches, + branches_missed: missed_branches, }) } } @@ -84,7 +84,7 @@ impl PerfCounters { let tlbd_miss_count = self.tlbd_miss_counter.read()? as f64 / num_iter; let miss_count = self.l1d_miss_counter.read()? as f64 / num_iter; let branches_count = self.branches.read()? as f64 / num_iter; - let missed_branches_count = self.branch_misses.read()? as f64 / num_iter; + let missed_branches_count = self.branches_missed.read()? as f64 / num_iter; Ok(CounterValues { l1d_access_count, @@ -123,9 +123,9 @@ impl EventListener for PerfCounterPerBench { fn name(&self) -> &'static str { PERF_CNT_EVENT_LISTENER_NAME } - fn on_event(&mut self, event: BingganEvents) { + fn on_event(&mut self, event: PluginEvents) { match event { - BingganEvents::BenchStart { bench_id } => { + PluginEvents::BenchStart { bench_id } => { self.perf_per_bench .insert_if_absent(bench_id, || PerfCounters::new().ok()); let perf = self.perf_per_bench.get_mut(bench_id).unwrap(); @@ -133,7 +133,7 @@ impl EventListener for PerfCounterPerBench { perf.enable(); } } - BingganEvents::BenchStop { bench_id, .. } => { + PluginEvents::BenchStop { bench_id, .. } => { let perf = self.perf_per_bench.get_mut(bench_id).unwrap(); if let Some(perf) = perf { perf.disable(); diff --git a/src/report/mod.rs b/src/report/mod.rs index 9772550..2b6a672 100644 --- a/src/report/mod.rs +++ b/src/report/mod.rs @@ -3,7 +3,7 @@ //! //! The `report` module contains reporters that use the plugin system via the [EventListener](crate::plugins::EventListener) //! trait. -//! You can set the reporter by registering at [BenchRunner::get_event_manager] . +//! You can set the reporter by registering at [BenchRunner::get_plugin_manager] . //! Use [REPORTER_PLUGIN_NAME](crate::report::REPORTER_PLUGIN_NAME) as the name of a reporter, to overwrite the existing //! @@ -28,7 +28,7 @@ use format::{bytes_to_string, format_duration_or_throughput}; use crate::{ bench::Bench, - plugins::{BingganEvents, EventManager}, + plugins::{PluginEvents, PluginManager}, stats::compute_diff, write_results::fetch_previous_run_and_write_results_to_disk, }; @@ -42,7 +42,7 @@ pub(crate) fn report_group<'a>( group_name: Option<&str>, benches: &mut [Box + 'a>], output_value_column_title: &'static str, - events: &mut EventManager, + events: &mut PluginManager, ) { if benches.is_empty() { return; @@ -54,7 +54,7 @@ pub(crate) fn report_group<'a>( fetch_previous_run_and_write_results_to_disk(&mut result); results.push(result); } - events.emit(BingganEvents::GroupStop { + events.emit(PluginEvents::GroupStop { runner_name, group_name, results: &results, diff --git a/src/report/plain_reporter.rs b/src/report/plain_reporter.rs index 5fa3ec2..bc4c989 100644 --- a/src/report/plain_reporter.rs +++ b/src/report/plain_reporter.rs @@ -4,7 +4,7 @@ use yansi::Paint; use super::{avg_median_str, memory_str, min_max_str, BenchStats, REPORTER_PLUGIN_NAME}; use crate::{ - plugins::{BingganEvents, EventListener}, + plugins::{EventListener, PluginEvents}, report::{check_and_print, PrintOnce}, }; @@ -19,6 +19,7 @@ use crate::{ #[derive(Clone)] pub struct PlainReporter { print_runner_name_once: Option, + print_num_iter: bool, } impl EventListener for PlainReporter { @@ -28,10 +29,10 @@ impl EventListener for PlainReporter { fn name(&self) -> &'static str { REPORTER_PLUGIN_NAME } - fn on_event(&mut self, event: BingganEvents) { + fn on_event(&mut self, event: PluginEvents) { match event { - BingganEvents::BenchStart { bench_id: _ } => {} - BingganEvents::GroupStart { + PluginEvents::BenchStart { bench_id: _ } => {} + PluginEvents::GroupStart { runner_name, group_name: Some(group_name), output_value_column_title: _, @@ -41,10 +42,12 @@ impl EventListener for PlainReporter { } println!("{}", group_name.black().on_yellow().invert().bold()); } - BingganEvents::GroupNumIters { num_iter } => { - println!("Num Iter {}", num_iter.bold()); + PluginEvents::GroupNumIters { num_iter } => { + if self.print_num_iter { + println!("Num Iter {}", num_iter.bold()); + } } - BingganEvents::GroupStop { + PluginEvents::GroupStop { runner_name: _, group_name: _, results, @@ -84,8 +87,14 @@ impl PlainReporter { pub fn new() -> Self { Self { print_runner_name_once: None, + print_num_iter: false, } } + /// Print the number of iterations for each benchmark group + pub fn print_num_iter(mut self, print: bool) -> Self { + self.print_num_iter = print; + self + } pub(crate) fn to_columns( &self, diff --git a/src/report/table_reporter.rs b/src/report/table_reporter.rs index 6f24d06..c0dd0ff 100644 --- a/src/report/table_reporter.rs +++ b/src/report/table_reporter.rs @@ -4,7 +4,7 @@ use yansi::Paint; use super::{avg_median_str, memory_str, min_max_str, REPORTER_PLUGIN_NAME}; use crate::{ - plugins::{BingganEvents, EventListener}, + plugins::{EventListener, PluginEvents}, report::{check_and_print, PrintOnce}, }; @@ -47,10 +47,10 @@ impl EventListener for TableReporter { fn name(&self) -> &'static str { REPORTER_PLUGIN_NAME } - fn on_event(&mut self, event: BingganEvents) { + fn on_event(&mut self, event: PluginEvents) { match event { - BingganEvents::BenchStart { bench_id: _ } => {} - BingganEvents::GroupStart { + PluginEvents::BenchStart { bench_id: _ } => {} + PluginEvents::GroupStart { runner_name, group_name, output_value_column_title: _, @@ -62,7 +62,7 @@ impl EventListener for TableReporter { println!("{}", group_name.black().on_yellow().invert().bold()); } } - BingganEvents::GroupStop { + PluginEvents::GroupStop { runner_name: _, group_name: _, results,