Run

Struct Run 

Source
pub struct Run { /* private fields */ }
Expand description

A benchmark run will execute a specific number of multithreaded iterations on every thread of a crate::ThreadPool.

A Run must first be configured, after which it can be executed. The run logic separates preparation (unmeasured) from execution (measured) phases.

§Execution Phases

  1. Thread Preparation: Each thread executes the thread preparation callback once
  2. Iteration Preparation: Each thread prepares state for every iteration (unmeasured)
  3. Measurement Begin: Measurement wrapper begin callback is called per thread
  4. Iteration Execution: All iterations are executed (measured)
  5. Measurement End: Measurement wrapper end callback is called per thread
  6. Cleanup: All cleanup state is dropped (unmeasured)

§Examples

Basic usage with atomic counter:

use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};

use many_cpus::ProcessorSet;
use par_bench::{Run, ThreadPool};

let mut pool = ThreadPool::new(&ProcessorSet::default());
let counter = Arc::new(AtomicU64::new(0));

let run = Run::new()
    .prepare_thread({
        let counter = Arc::clone(&counter);
        move |_| Arc::clone(&counter)
    })
    .prepare_iter(|args| Arc::clone(args.thread_state()))
    .iter(|mut args| {
        args.iter_state().fetch_add(1, Ordering::Relaxed);
    });

let results = run.execute_on(&mut pool, 1000);
println!("Executed in: {:?}", results.mean_duration());

With measurement wrapper for custom metrics:

use std::time::Instant;

use many_cpus::ProcessorSet;
use par_bench::{Run, ThreadPool};

let mut pool = ThreadPool::new(&ProcessorSet::default());

let run = Run::new()
    .measure_wrapper(|_| Instant::now(), |start| start.elapsed())
    .iter(|_| {
        // Simulate some work
        std::hint::black_box((0..100).sum::<i32>());
    });

let results = run.execute_on(&mut pool, 1000);

// Access per-thread measurement data
for elapsed in results.measure_outputs() {
    println!("Thread execution time: {:?}", elapsed);
}

Implementations§

Source§

impl Run

Source

pub fn new() -> RunInitial

Creates a new benchmark run and starts the process of configuring it.

The type uses a fluent API with enforced ordering to configure the different callback functions that will be executed during the benchmark run. The type system ensures that methods are called in the correct order and that all required configuration is provided.

§Order of operations
  1. Start with Run::new(), which gives you an object you can use to configure the run.
  2. Optionally configure thread groups with groups()
  3. Optionally set thread preparation with prepare_thread()
  4. Optionally set iteration preparation with prepare_iter()
  5. Optionally set measurement wrappers with measure_wrapper()
  6. Required: Set the benchmark function with iter()
  7. Required: Execute the run with either execute_on() or [execute_criterion_on()][crate::ConfiguredRun::execute_criterion_on].

You can skip optional steps but cannot go back in the sequence.

§Examples
use par_bench::Run;

let run = Run::new().iter(|_| {
    // Benchmark work goes here
    std::hint::black_box(42 * 42);
});

Trait Implementations§

Source§

impl Debug for Run

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Run

§

impl RefUnwindSafe for Run

§

impl Send for Run

§

impl Sync for Run

§

impl Unpin for Run

§

impl UnwindSafe for Run

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V