Skip to main content

BenchmarkWork

Trait BenchmarkWork 

Source
pub trait BenchmarkWork:
    Clone
    + Send
    + Sync
    + 'static {
    type State: Send + 'static;

    // Required methods
    fn init(&self) -> impl Future<Output = Self::State> + Send;
    fn work(
        &self,
        state: &mut Self::State,
    ) -> impl Future<Output = WorkResult> + Send;

    // Provided method
    fn cleanup(&self, _state: Self::State) -> impl Future<Output = ()> + Send { ... }
}
Expand description

Worker lifecycle for the request/response benchmark pattern.

The framework:

  1. Clones self once per worker task — Arc-backed types (reqwest::Client, Arc<Pool>, etc.) remain shared across workers.
  2. Calls init once per worker to create per-worker state.
  3. Calls work in a loop (after rate limiting).
  4. Calls cleanup once when the benchmark ends.

§Minimal example

#[derive(Clone)]
struct HttpWork {
    client: reqwest::Client,  // Arc-backed — shared across all workers
    url: String,
}

impl BenchmarkWork for HttpWork {
    type State = ();  // no per-worker state needed

    async fn init(&self) -> () {}

    async fn work(&self, _: &mut ()) -> WorkResult {
        let start = now_unix_ns_estimate();
        match self.client.get(&self.url).send().await {
            Ok(r) if r.status().is_success() =>
                WorkResult::success(now_unix_ns_estimate() - start),
            Ok(r)  => WorkResult::error(format!("HTTP {}", r.status())),
            Err(e) => WorkResult::error(e.to_string()),
        }
    }
}

// One line, no closures, no manual cloning:
Benchmark::new().rate(1000.0).workers(4).work(HttpWork { client, url }).run().await

§Per-worker state example

#[derive(Clone)]
struct DbWork { pool: Arc<Pool> }

impl BenchmarkWork for DbWork {
    type State = PooledConn;  // one checked-out connection per worker

    async fn init(&self) -> PooledConn {
        self.pool.acquire().await.unwrap()  // once per worker
    }

    async fn work(&self, conn: &mut PooledConn) -> WorkResult {
        // reuse the same connection every iteration — no checkout overhead
        todo!()
    }

    async fn cleanup(&self, conn: PooledConn) {
        conn.close().await;
    }
}

Required Associated Types§

Source

type State: Send + 'static

Per-worker state created by init and passed to every work call.

Use () when no per-worker state is needed.

Required Methods§

Source

fn init(&self) -> impl Future<Output = Self::State> + Send

Create per-worker state. Called once before the work loop starts.

Source

fn work( &self, state: &mut Self::State, ) -> impl Future<Output = WorkResult> + Send

Execute one unit of work. Called in a loop after rate limiting.

Provided Methods§

Source

fn cleanup(&self, _state: Self::State) -> impl Future<Output = ()> + Send

Clean up per-worker state when the benchmark ends.

Default: drops the state.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§