pocket_watch/summary

This module allows you to run a function many times (with an optional warmup) and collect aggregate statistics about the run times.

Examples:

Run a function multiple times and aggregate the results:

use <- pocket_watch.summary_simple("simple summary", runs: 100, warmup: 0)

function_thats_usually_fast_but_occasionally_really_slow()
// pocket_watch [simple summary]: min: 210.0ns, max: 100.02ms, median: 6.0ms, mean: 12.77ms
//                                warmup: 0/0.0ns, total post-warmup: 100/1.28s

Aggregate with a custom callback:

use <- summary.callback(
  runs: 10_000,
  warmup: 100,
  with: summary.label("sprint", summary.show_rates),
)

function_that_gets_faster_over_time()
// pocket_watch [sprint]: warmup: 6.6/s, post-warmup: 13.63/s

Collect a summary to work with directly:

let Summary(
  values:, // List of return values from each run
  times:, // List of times from each run
  runs:, // Number of runs
  warmup_runs:, // Number of warmup runs
  warmup:, // Warmup time elapsed
  total:, // Total (post-warmup) time elapsed
  min:, // Fastest run time
  max:, // Slowest run time
  median:, // Median run time
  mean:, // Mean/average run time
) = summary.collect(runs: 100, warmup: 0, time: yet_another_function)

Types

Type for holding statistics generated by collect.

pub type Summary(value) {
  Summary(
    values: List(value),
    times: List(duration.Duration),
    runs: Int,
    warmup_runs: Int,
    warmup: duration.Duration,
    total: duration.Duration,
    min: duration.Duration,
    max: duration.Duration,
    median: duration.Duration,
    mean: duration.Duration,
  )
}

Constructors

Values

pub fn callback(
  runs n: Int,
  warmup warmup: Int,
  with callback: fn(Summary(a)) -> String,
  time body: fn() -> a,
) -> a

Note: Be aware of side effects when using any of the summary functions. body will be called multiple times and any side effects will be triggered each time.

Run a function warmup times and discard the return values, then run it again n times and use the provided callback to log the generated Summary to stderr.

This function returns the first value it collects.

Examples:

{
  use <- summary.callback(runs: 100, warmup: 10, with: summary.show_overall)

  string.repeat("meow ", 1_000_000)
}
// runs: 100, warmup: 30.78ms, total (ex. warmup): 222.19ms
pub fn collect(
  runs runs: Int,
  warmup warmup_runs: Int,
  time body: fn() -> a,
) -> Summary(a)

Note: Be aware of side effects when using any of the summary functions. body will be called multiple times and any side effects will be triggered each time.

Run a function warmup times and discard the return values, then run it again n times and return a Summary, which contains:

  • Aggregate statistics (min, max, median, mean, etc.)
  • Per-run times
  • Collected return values from each run

Examples:

let summary = {
  use <- summary.collect(runs: 100, warmup: 0)

  string.repeat("meow ", 1_000_000)
}

summary.show_timings(summary) |> io.println_error
// min: 1.49ms, max: 4.13ms, median: 2.03ms, mean: 2.11ms
pub fn label(
  label label: String,
  this callback: fn(Summary(a)) -> String,
) -> fn(Summary(a)) -> String

Prepends a simple label to a Summary(_) -> String function.

pub fn show_all(summary: Summary(value)) -> String

Returns a String containing all aggregate information from a Summary.

Examples:

"min: 1.0ms, max: 2.0ms, median: 1.5ms, mean: 1.5ms, runs: 10_000, warmup: 800.0ms, total (ex. warmup): 15.0s"
pub fn show_overall(summary: Summary(value)) -> String

Returns a String containing the overall information from a Summary.

Examples:

"runs: 1000, warmup: 200.0ms, total (ex. warmup): 2.0s"
pub fn show_rates(summary: Summary(value)) -> String

Returns a String containing warmup and post-warmup rates calculated from a Summary.

Examples:

"warmup: 10.0/s, post-warmup: 30.0/s"
pub fn show_timings(summary: Summary(value)) -> String

Returns a String containing the aggregate timing information from a Summary.

Examples:

"min: 1.0ms, max: 2.0ms, median: 1.5ms, mean: 1.5ms"
pub fn simple(
  label label: String,
  runs n: Int,
  warmup warmup: Int,
  time body: fn() -> a,
) -> a

Note: Be aware of side effects when using any of the summary functions. body will be called multiple times and any side effects will be triggered each time.

Run a function warmup times and discard the return values, then run it again n times and log the generated Summary to stderr.

This function returns the first value it collects.

Examples:

{
  use <- summary.simple(label: "test", runs: 100, warmup: 0)

  string.repeat("meow ", 1_000_000)
}
// pocket_watch [test]: min: 1.45ms, max: 3.28ms, median: 2.02ms, mean: 2.04ms
//                      runs: 100, warmup: 0.0ns, total (ex. warmup): 203.73ms
Search Document